• bzoj5019: [Snoi2017]遗失的答案


    我觉得可能很多人的做法都很傻逼 这毒瘤路牌好好的把我都搞懵逼了

    首先先考虑质因数分解G、L,选出的数中质因子的最小次幂和最大次幂要分别等于G、L对应质因子的次幂

    可以发现L的质因子个数不会超过8个,n之内满足条件的数的个数不会超过800,考虑状压DP

    当没有必选x的限制时,f[i][j][k]表示前i个合法的数,每个质因数下界是否满足,上界是否满足。预处理每个合法的数是否顶上下界,转移显然,实际上第一维可以省去,我做的时候直接把后两维并一起了

    现在思考询问,对于固定x要选如何快速得到,想法是直接预处理所有x的答案。

    考虑补集转化,求不带x的方案数

    有一种非常毒瘤的做法就是分别出来前缀和后缀,询问的时候直接FWT做或卷积,预处理的空间又大跑得又龟除了完全不动脑没有什么优点

    不过看到了一种很有意思很优美的分治做法,先进行[l,mid]的影响,然后去递归得到[mid+1,r]的答案,做完以后通过记录上一层的答案重新进行当前层,进行[mid+1,r]的影响,然后递归得到[l,mid]的答案,这个东西理论的时空复杂度应该是O(len*loglen*(2^plen)^2)略小于FWT

    我自己的做法是这样的:(不用补集转化)考虑对于必选x,把它的对应的状态用zt表示,那么现在要求的是li^zt的每个超集不包含x的方案数。不难发现,除非是满集,否则li^zt的超集一定不包含x,这里先预处理。考虑如何把满集的贡献计算。只需要去掉必须用x的方案,那么x是可有可无的,直接减除二就可以了。

    形式化的:li^zt的每个超集不包含x的方案数 = 超集中非满集不包含x的方案数 + 满集不包含x的方案数

    = 超集中非满集的方案数 + (满集的方案数 - 必须用x的方案数)/2

    = 超集中非满集的方案数 + (满集的方案数 - 超集中非满集的方案数)/2

    枚举子集统计一下超集和(不含满集)就完了

    至于网上算至少然后带个容斥系数的,您就图个乐子看吧

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<map>
    
    #define ft first
    #define sd second
    using namespace std;
    const int _=1e2;
    const int taxp=8;
    const int maxp=taxp+2;
    const int maxz=(1<<2*taxp)+_;
    const int maxn=8e2+10;
    typedef long long LL;
    typedef pair<int,int> pp;
    const int mod=1e9+7;
    inline int ad(int x,int y){return (x>=mod-y)?x-mod+y:x+y;}
    inline int re(int x,int y){return (x<y)?x-y+mod:x-y;};
    int n,G,L;
    
    int plen,p[maxp],q[2*maxp];
    void divi()
    {
        plen=0; int K=L;
        for(int i=2;i*i<=K;i++)
            if(K%i==0){p[++plen]=i;while(K%i==0)K/=i;}
        if(K!=1)p[++plen]=K;
        sort(p+1,p+plen+1);
            
        K=L;
        for(int i=1;i<=plen;i++)
            if(K%p[i]==0){while(K%p[i]==0)K/=p[i],q[i+plen]++;}
        K=G;
        for(int i=1;i<=plen;i++)
            if(K%p[i]==0){while(K%p[i]==0)K/=p[i],q[i]++;}
    }
    int len;pp num[maxn]; map<int,int>leg;
    void getnum(int k,int d,int s)
    {
        if(k==plen+1){num[++len]=make_pair(d,s);return ;}
        for(int i=q[k],g=int(pow(p[k],q[k])); i<=q[plen+k]; i++,g*=p[k])
            if((LL)d*g<=n)getnum(k+1,d*g, s | ((i==q[k])?(1<<k-1):0) | ((i==q[plen+k])?(1<<plen+k-1):0) );
    }
    
    int f[maxz],d[maxz];
    void DP()
    {
        f[0]=1; int li=(1<<plen*2)-1;
        for(int i=0;i<len;i++)
            for(int zt=li;zt>=0;zt--)
                if(f[zt])f[zt|num[i+1].sd]=ad(f[zt|num[i+1].sd],f[zt]);
        
        for(int zt=0;zt<li;zt++)
            if(f[zt])
            {
                for(int ut=zt;ut;ut=(ut-1)&zt)d[ut]=ad(d[ut],f[zt]);
                d[0]=ad(d[0],f[zt]);
            }
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&G,&L);
        if(L%G==0)
        {
            divi();
            getnum(1,1,0);
            sort(num+1,num+len+1);
            for(int i=1;i<=len;i++)leg[num[i].ft]=i;
            DP();
        }
        
        int Q,x;
        scanf("%d",&Q); int li=(1<<plen*2)-1;
        while(Q--)
        {
            scanf("%d",&x);    if(L%G!=0){puts("0");continue;}
            if(!leg.count(x)){puts("0");}
            else
            {
                int D=d[li^num[leg[x]].sd];
                printf("%d
    ",ad((LL)re(f[li],D)*(mod/2+1)%mod,D));
            }
        }
        
        return 0;
    }
    View Code
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<map>
    
    #define ft first
    #define sd second
    using namespace std;
    const int _=1e2;
    const int taxp=8;
    const int maxp=taxp+2;
    const int maxz=(1<<2*taxp)+_;
    const int maxn=8e2+10;
    typedef long long LL;
    typedef pair<int,int> pp;
    const int mod=1e9+7;
    inline int ad(int x,int y){return (x>=mod-y)?x-mod+y:x+y;}
    inline int re(int x,int y){return (x<y)?x-y+mod:x-y;};
    int n,G,L;
    
    int plen,p[maxp],q[2*maxp];
    void divi()
    {
        plen=0; int K=L;
        for(int i=2;i*i<=K;i++)
            if(K%i==0){p[++plen]=i;while(K%i==0)K/=i;}
        if(K!=1)p[++plen]=K;
        sort(p+1,p+plen+1);
            
        K=L;
        for(int i=1;i<=plen;i++)
            if(K%p[i]==0){while(K%p[i]==0)K/=p[i],q[i+plen]++;}
        K=G;
        for(int i=1;i<=plen;i++)
            if(K%p[i]==0){while(K%p[i]==0)K/=p[i],q[i]++;}
    }
    int len;pp num[maxn]; map<int,int>leg;
    void getnum(int k,int d,int s)
    {
        if(k==plen+1){num[++len]=make_pair(d,s);return ;}
        for(int i=q[k],g=int(pow(p[k],q[k])); i<=q[plen+k]; i++,g*=p[k])
            if((LL)d*g<=n)getnum(k+1,d*g, s | ((i==q[k])?(1<<k-1):0) | ((i==q[plen+k])?(1<<plen+k-1):0) );
    }
    
    int li,f[30][maxz],sum,as[maxn];
    void flu(int *a,int i)
    {
        for(int zt=li;zt>=0;zt--)
            if(a[zt])a[zt|num[i].sd]=ad(a[zt|num[i].sd],a[zt]);
    }
    void dc(int k,int l,int r)
    {
        if(l==r)
        {
            if(l==len)
            {
                memcpy(f[k],f[k-1],sizeof(f[k]));
                flu(f[k],l); sum=f[k][li];
            }
            as[l]=re(sum,f[k-1][li]);
            return ;
        }
        int mid=(l+r)/2;
        
        memcpy(f[k],f[k-1],sizeof(f[k]));
        for(int i=l;i<=mid;i++)flu(f[k],i);
        dc(k+1,mid+1,r);
        
        memcpy(f[k],f[k-1],sizeof(f[k]));
        for(int i=mid+1;i<=r;i++)flu(f[k],i);
        dc(k+1,l,mid);
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&G,&L);
        if(L%G==0)
        {
            divi();
            getnum(1,1,0);
            sort(num+1,num+len+1);
            for(int i=1;i<=len;i++)leg[num[i].ft]=i;
            li=(1<<plen*2)-1;
            f[0][0]=1;dc(1,1,len);
        }
        
        int Q,x;
        scanf("%d",&Q);
        while(Q--)
        {
            scanf("%d",&x);    if(L%G!=0){puts("0");continue;}
            if(!leg.count(x)){puts("0");}
            else printf("%d
    ",as[leg[x]]);
        }
        
        return 0;
    }
    分治
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<map>
    
    #define ft first
    #define sd second
    using namespace std;
    const int _=1e2;
    const int taxp=8;
    const int maxp=taxp+2;
    const int maxz=(1<<2*taxp)+_;
    const int maxn=8e2+10;
    typedef long long LL;
    typedef pair<int,int> pp;
    const int mod=1e9+7;
    inline int ad(int x,int y){return (x>=mod-y)?x-mod+y:x+y;}
    inline int re(int x,int y){return (x<y)?x-y+mod:x-y;};
    int n,G,L;
    
    int plen,p[maxp],q[2*maxp];
    void divi()
    {
        plen=0; int K=L;
        for(int i=2;i*i<=K;i++)
            if(K%i==0){p[++plen]=i;while(K%i==0)K/=i;}
        if(K!=1)p[++plen]=K;
        sort(p+1,p+plen+1);
            
        K=L;
        for(int i=1;i<=plen;i++)
            if(K%p[i]==0){while(K%p[i]==0)K/=p[i],q[i+plen]++;}
        K=G;
        for(int i=1;i<=plen;i++)
            if(K%p[i]==0){while(K%p[i]==0)K/=p[i],q[i]++;}
    }
    int len;pp num[maxn]; map<int,int>leg;
    void getnum(int k,int d,int s)
    {
        if(k==plen+1)
        {
            num[++len]=make_pair(d,s);
    //        printf("%d %d
    ",d,s);
            return ;
        }
        for(int i=q[k],g=int(pow(p[k],q[k])); i<=q[plen+k]; i++,g*=p[k])
            if((LL)d*g<=n)getnum(k+1,d*g, s | ((i==q[k])?(1<<k-1):0) | ((i==q[plen+k])?(1<<plen+k-1):0) );
    }
    
    void FWT(int *a,int n,int op)
    {
        for(int i=1;i<n;i<<=1)
            for(int j=0;j<n;j+=(i<<1))
                for(int k=0;k<i;k++)
                    if(op==1)a[j+k+i]=ad(a[j+k+i],a[j+k]);
                    else a[j+k+i]=re(a[j+k+i],a[j+k]);
    }
    int f[maxn][maxz],g[maxn][maxz],h[maxz],d[maxn];
    void DP()
    {
        f[0][0]=1; int li=(1<<plen*2)-1;
        for(int i=0;i<len;i++)
            for(int j=0;j<=li;j++)
                if(f[i][j])
                {
                    f[i+1][j|num[i+1].sd]=ad(f[i+1][j|num[i+1].sd],f[i][j]);
                    f[i+1][j]=ad(f[i+1][j],f[i][j]);
                }
        
        g[len+1][0]=1;
        for(int i=len+1;i>1;i--)
            for(int j=0;j<=li;j++)
                if(g[i][j])
                {
                    g[i-1][j|num[i-1].sd]=ad(g[i-1][j|num[i-1].sd],g[i][j]);
                    g[i-1][j]=ad(g[i-1][j],g[i][j]);
                }
        
        d[1]=g[2][li],d[len]=f[len-1][li];
        for(int i=2;i<len;i++)
        {
            FWT(f[i-1],li+1,1),FWT(g[i+1],li+1,1);
            for(int j=0;j<=li;j++)h[j]=(LL)f[i-1][j]*g[i+1][j]%mod;
            FWT(h,li+1,-1);
            d[i]=h[li];
        }
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&G,&L);
        if(L%G==0)
        {
            divi();
            getnum(1,1,0);
            sort(num+1,num+len+1);
            for(int i=1;i<=len;i++)leg[num[i].ft]=i;
            DP();
        }
        
        int Q,x;
        scanf("%d",&Q); int li=(1<<plen*2)-1;
        while(Q--)
        {
            scanf("%d",&x);    if(L%G!=0){puts("0");continue;}
            if(!leg.count(x)){puts("0");}
            else printf("%d
    ",re(f[len][li],d[leg[x]]));
        }
        
        return 0;
    }
    FWT
  • 相关阅读:
    Lock、Synchronized锁解析
    js多个计时器互不影响触发
    php Excel文件导入 Spreadsheet_Excel_Reader
    Tcp/ip简介
    对称加密和非对称加密
    AFNetworking 3.0迁移指南
    从 Objective-C 里的 Alloc 和 AllocWithZone 谈起
    iOS 沙盒
    SDWebImage解析
    dSYM文件
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10728514.html
Copyright © 2020-2023  润新知