CF 1313

偷偷摸一套题解。。。

CF 1313

A

给定三个颜色的数量,问能凑出多少钟不同的搭配

贪心,先拿最多的颜色搭配出需要颜色最少的组合

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
        inline int read()
        {
            int x=0;char ch,f=1;
            for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
            if(ch=='-') f=0,ch=getchar();
            while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 
            return f?x:-x;
        }
        const int N=1e5+10,p=998244353;
        int haku;
        int a[4],sum;
        inline void main()
        {
            haku=read();
            while(haku--)
            {
                a[1]=read(),a[2]=read(),a[3]=read();
                sort(a+1,a+4);
                sum=0;
                if(a[1]) --a[1],++sum;
                if(a[2]) --a[2],++sum;
                if(a[3]) --a[3],++sum;
                if(a[2]&&a[3]) --a[2],--a[3],++sum;
                if(a[1]&&a[3]) --a[1],--a[3],++sum;
                if(a[1]&&a[2]) --a[1],--a[2],++sum;
                if(a[1]&&a[2]&&a[3]) ++sum;
                printf("%lld\n",sum);
            }
        }
    }
    signed main()
    {
        red::main();
        return 0;
    }

B

最小排名:尽量让其他的人\(sum=x+y+1\),有些第一轮的数字做不到就让这些数字先把第二轮最小的浪费掉,得到排名\(=max(1,x+y-n+1)\)

最大排名:尽量让其他人\(sum=x+y\),做不到的同理花掉最小的数字,得到排名\(=min(n,z-1)\)

\(x==1,y==1\)\(x==n,y==n\) 的时候都要特判。。

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
        inline int read()
        {
            int x=0;char ch,f=1;
            for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
            if(ch=='-') f=0,ch=getchar();
            while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 
            return f?x:-x;
        }
        const int N=1e5+10,p=998244353;
        int haku;
        int n,x,y,z;
        inline void main()
        {
            haku=read();
            while(haku--)
            {
                n=read(),x=read(),y=read();
                if(x==1&&y==1)
                {
                    puts("1 1");
                    continue;
                }
                if(x==n&&y==n)
                {
                    printf("%lld %lld\n",n,n);
                    continue;
                }
                z=x+y;
                if(x>y) swap(x,y);
                int sum1=0,sum2=0;
                sum1=max(1ll,z-n+1);
                sum2=min(z-1,n);
                printf("%lld %lld\n",sum1,sum2);
            }
        }
    }
    signed main()
    {
        red::main();
        return 0;
    }
    /*
    1
    5 5 1
     
    */

C

\(s1[i]\)表示以\(i\)为峰,\(1-i\)的和,\(s2[i]\)表示以\(i\)为峰,\(i-n\)的和,枚举中间点拼接一下

记得打完暴力打正解的时候把数组开大。。

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
        inline int read()
        {
            int x=0;char ch,f=1;
            for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
            if(ch=='-') f=0,ch=getchar();
            while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 
            return f?x:-x;
        }
        const int N=5e5+10,p=998244353;
        int haku;
        int n,sum,ret,pos;
        int a[N],c[N];
        int st[N],top;
        int s1[N],s2[N];
        inline void main()
        {
            n=read();
            for(int i=1;i<=n;++i) a[i]=read();
            for(int i=1;i<=n;++i)
            {
                s1[i]=s1[i-1];
                while(top&&a[i]<=a[st[top]])
                {
                    s1[i]-=(st[top]-st[top-1])*a[st[top]];
                    --top;
                }
                s1[i]+=(i-st[top])*a[i];
                st[++top]=i;
            }
            st[top=0]=n+1;
            for(int i=n;i;--i)
            {
                s2[i]=s2[i+1];
                while(top&&a[i]<=a[st[top]])
                {
                    s2[i]-=(st[top-1]-st[top])*a[st[top]];
                    --top;
                }
                s2[i]+=(st[top]-i)*a[i];
                st[++top]=i;
            }
            for(int i=0;i<=n;++i)
            {
                if(s1[i]+s2[i+1]>ret)
                {
                    pos=a[i]>a[i+1]?i:i+1;
                    ret=s1[i]+s2[i+1];
                }
            }
            c[pos]=a[pos];
            for(int i=pos-1;i;--i) c[i]=min(a[i],c[i+1]);
            for(int i=pos+1;i<=n;++i) c[i]=min(a[i],c[i-1]);
            for(int i=1;i<=n;++i) printf("%lld ",c[i]); 
        }
    }
    signed main()
    {
        red::main();
        return 0;
    }

D

每个区间只会被覆盖\(k\)次,撞鸭一个区间被哪些线段覆盖,\(f[i][s]\)表示区间\([i,i+1]\)被s种线段覆盖后的最大价值

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    #define ls(p) (p<<1)
    #define rs(p) (p<<1|1)
    #define mid ((l+r)>>1)
        inline int read()
        {
            int x=0;char ch,f=1;
            for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
            if(ch=='-') f=0,ch=getchar();
            while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 
            return f?x:-x;
        }
        const int N=2e5+10,inf=1e9+7;
        int n,m,k,s,now,ret;
        int c[N],num;
        int f[N],cnt[N];
        int l[N],r[N],id[N]; 
        vector<int> d[N];
        inline void main()
        {
            n=read(),m=read(),k=read();s=1<<k;
            for(int i=1;i<s;++i) cnt[i]=cnt[i>>1]+(i&1);
            for(int i=1;i<=n;++i)
            {
                l[i]=read(),r[i]=read()+1;
                c[++num]=l[i],c[++num]=r[i];
            }
            c[++num]=m;c[++num]=1;
            sort(c+1,c+num+1);num=unique(c+1,c+num+1)-c-1;
            for(int i=1;i<=n;++i)
            {
                l[i]=lower_bound(c+1,c+num+1,l[i])-c;
                r[i]=lower_bound(c+1,c+num+1,r[i])-c;
                for(int j=l[i];j<r[i];++j) d[j].push_back(i);
            }
            memset(f,0xcf,sizeof(f));f[0]=0;
            for(int i=1;i<num;++i)
            {
                for(int j=0;j<k;++j)
                    if(id[j]&&r[id[j]]<=i) now^=1<<j,id[j]=0;
                for(int j=0;j<s;++j)
                    if((j|now)!=now) f[j&now]=max(f[j&now],f[j]),f[j]=-inf;
                for(int j=0;j<d[i].size();++j) if(l[d[i][j]]==i)
                {
                    for(int p=0;p<k;++p) if(!id[p])
                    {
                        for(int l=s-1;~l;--l)
                        {
                            f[l|1<<p]=f[l];
                        }
                        id[p]=d[i][j],now|=1<<p;break;
                    }
                }
                for(int j=0;j<s;++j)
                    f[j]+=(cnt[j]&1)*(c[i+1]-c[i]);
            }
            for(int i=0;i<s;++i) ret=max(ret,f[i]);
            printf("%lld\n",ret);
        }
    }
    signed main()
    {
        red::main();
        return 0;
    }

E

\(f[i]\)表示\(a\)串以\(i\)开头与\(s\)串的最长公共前缀,\(g[i]\)表示\(b\)串以\(i\)结尾与\(s\)串的最长公共后缀

由于两个区间必须有交,所以\(l_1<=r_2\)

由于两个区间长度之和等于\(m\),所以\(r_2<=l_1+m-2\)

对于一对固定的\(l_1,r_2\),对答案的贡献为\(f[l_1]=g[r_2]-m+1\)

\[ret=\sum\limits_{i=1}^{n}\sum\limits_{j=i}^{min(n,i+m+2)}max(f[i]+g[j]-m+1,0)\]

我们开两个\(bit\),用来记录\([i,i+m-2]\)\(g[j]\)的数量和加和

显然对于\(g[j]+1<m-f[i]\)的部分我们是不需要的,我们每次先对答案加上\([m-f[i],m]\)区间内的\(g[j]\)的和

再加上 \(数量*(f[i]-m+1)\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
    inline int read()
    {
        int x=0;char ch,f=1;
        for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
        if(ch=='-') f=0,ch=getchar();
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 
        return f?x:-x;
    }
    const int N=1e6+10,inf=1e9+7,base=131,mod=1e9+7;
    int n,m,t,ret;
    char a[N],b[N],s[N];
    int nxt[N],f[N],g[N];
    int pw[N],ha[N],hs[N];
    inline void prepare(char *a,int *f)
    {
        int len=max(n,m);
        for(int i=pw[0]=1;i<=len;++i) pw[i]=pw[i-1]*base%mod;
        for(int i=1;i<=n;++i) ha[i]=(ha[i-1]*base+a[i])%mod;
        for(int i=1;i<=m;++i) hs[i]=(hs[i-1]*base+s[i])%mod;
        for(int i=1;i<=n;++i)
        {
            int l=i,r=n;
            while(l<=r)
            {
                int t1=(ha[mid]-ha[i-1]*pw[mid-i+1]%mod+mod)%mod;
                int t2=hs[mid-i+1];
                if(t1==t2) f[i]=mid-i+1,l=mid+1;
                else r=mid-1;
            }
            f[i]=min(f[i],m-1);
        }
    }
    struct BIT
    {
        int tr[N];
        BIT(){memset(tr,0,sizeof(tr));}
        inline void update(int p,int k)
        {
            for(p++;p<N;p+=p&(-p)) tr[p]+=k;
        }
        inline int query(int p)
        {
            int ret=0;
            for(p++;p;p-=p&(-p)) ret+=tr[p];
            return ret;
        }
    }bit[2];
    inline void main()
    {
        n=read(),m=read();
        scanf("%s%s%s",a+1,b+1,s+1);
        prepare(a,f);
        reverse(s+1,s+m+1);reverse(b+1,b+n+1);
        prepare(b,g);
        reverse(g+1,g+n+1);
        for(int i=n;i;--i)
        {
            bit[0].update(g[i],1);
            bit[1].update(g[i],g[i]);
            if(i+m-1<=n)
            {
                bit[0].update(g[i+m-1],-1);
                bit[1].update(g[i+m-1],-g[i+m-1]);
            }
            int v=m-f[i];
            ret+=bit[1].query(m)-bit[1].query(v-1);
            ret-=(bit[0].query(m)-bit[0].query(v-1))*(v-1);
        }
        printf("%lld\n",ret);
    }
}
signed main()
{
    red::main();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/knife-rose/p/12359860.html
cf