E Enigmatic Partition 2020牛客暑期多校训练营(第八场)

https://ac.nowcoder.com/acm/contest/5673/E

设我们要算出f[1-n],那么枚举a,a+1,a+2的个数,要满足x*a+(a+1)*y+(a+2)*z=1-n的数量

提取一下,(x+y+z)*a+y+2*z=1-n的数量,其中a,x,y,z>=1

那我们先求出a<=sqrt(n)的所有情况,然后去枚举i,得到a<=r下,f[1-n]的增加的值,这里是nsqrt(n)的复杂度

然后我们就只要去算sqrt(n)

我们令s=x+y+z,t=y+2*z,由s*a+t<=n,s<=sqrt(n),

令c[s][t]为x+y+z=s,y+2*z=t 时的(x,y,z)构造的方案数,这个可以通过简单的枚举x,y,z得到,是nsqrt(n)的复杂度

然后枚举a=sqrt(n)->n,对于每个a枚举s*a<=n再枚举t<=2*s,这一段通过积分可以知道也是nsqrt(n)的复杂度

所以总复杂度还是nsqrt(n),就可以算出f[1-n]的所有值

#include
using namespace std;
int f[200005];
long long c[2005][2005];
long long S[200005];
int main(){
    int n=100000,r=(int)sqrt(n+0.5),a;
    for(a=1;a<=r;a++){
        for(int i=3*a+3;i<=n;i+=a)f[i]=1;
        for(int m=4*a+4;m<=n;m++)f[m]+=f[m-a-1];
        for(int m=4*a+5;m<=n;m++)f[m]+=f[m-a-2];
        for(int i=3*a+3;i<=n;i++)S[i]+=f[i],f[i]=0;
    }
    for(int x=1;x<=r;x++){
        for(int y=1;x+y<=r;y++){
            for(int z=1;x+y+z<=r;z++){
                c[x+y+z][y+2*z]++;
            }
        }
    }
    for(;a<=n;a++){
        for(int s=3;s*a<=n;s++){
            for(int t=3;t<=2*s;t++){
                if(s*a+t<=n)S[s*a+t]+=c[s][t];
                else break;
            }
        }
    }
    for(int i=1;i<=n;i++)S[i]+=S[i-1];
    int t;
    scanf("%d",&t);
    for(int ti=1;ti<=t;ti++){
        int l,r;
        scanf("%d%d",&l,&r);
        printf("Case #%d: %lld\n",ti,S[r]-S[l-1]);
    }
    return 0;
}

 

你可能感兴趣的:(巧妙暴力)