[bzoj3462]dzy loves math II 解题报告

来源:互联网 发布:数据的安全管理 编辑:程序博客网 时间:2024/04/28 17:41

这道题的题意是设S=ki=1pi,且n=ki=1xipi,xi1,求(x1,x2,...,xk)的个数。
对于任一(x1,x2,...,xk),显然其可射于(x1 modSp1,x2 modSp2,...,xk modSp3),而且有ki=1xipin(mod S)。对于后者,其实就是一个多重背包;然后从它到n就是将若干个S分成k份,这便是一个经典问题了。
那么主要的时间就都花在多重背包上了,2106以内的数质因子个数最多有7个,所以时间复杂度就是O(72S+7q)108

#include<cstdio>int f[15000000],fp[15000000];int prime[1505];bool p[1505];#include<iostream>using namespace std;#include<cmath>int a[10];#define Mod 1000000007typedef long long LL;void in(LL &x){    char c=getchar();    while(c<'0'||c>'9')c=getchar();    for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');}int inver(int x){    LL ans=1,pro=x;    for(int pow=Mod-2;pow;pow>>=1,pro=pro*pro%Mod)        if(pow&1)            ans=ans*pro%Mod;    return ans;}#include<cstring>int main(){    freopen("bzoj_3462.in","r",stdin);    freopen("bzoj_3462.out","w",stdout);    int S,q,i,root,j;    scanf("%d%d",&S,&q);    //线筛     for(i=2,root=sqrt(S);i<=root;++i){        if(!p[i]){            prime[++prime[0]]=i;            if(S%i==0){                //cout<<"Get:"<<i<<endl;                a[++a[0]]=i;                if((S/=i)%i==0){                    while(q--)puts("0");                    return 0;                }            }        }        for(j=1;j<=prime[0]&&prime[j]*i<=root;++j){            p[i*prime[j]]=1;            if(i%prime[j]==0)break;        }    }    if(S!=1)a[++a[0]]=S;    S=1;    for(i=a[0];i;--i)S*=a[i];    //背包     int sum=S,bagsum,k;    f[0]=1;    for(i=a[0];i;--i,sum+=S){    //for(i=1;i<=a[0];++i){        memcpy(fp,f,sizeof(int)*(sum+1));        memset(f,0,sizeof(int)*a[i]);        for(j=a[i];j--;){            bagsum=fp[j];            for(k=j;k<S;){                f[k+=a[i]]=bagsum;                bagsum=(bagsum+fp[k])%Mod;            }            for(k+=a[i];k<=sum;k+=a[i]){                //cout<<k<<endl;                f[k]=(bagsum-fp[k-S-a[i]])%Mod;                bagsum=(f[k]+fp[k])%Mod;            }        }        /*printf("----%d----\n",a[i]);        for(k=0;k<=sum;++k)printf("f(%d)=%d\n",k,f[k]);*/    }    //逆元     int inv[10];    for(i=a[0]-1;i;--i)inv[i]=inver(i);    //for(i=1;i<a[0];++i)printf("%d*%d=%I64d\n",i,inv[i],(LL)i*inv[i]%Mod);    //处理询问     int ans;    LL pro,n,N;    while(q--){        in(n);        ans=0,i=n%S,N=(n-i)/S,pro=1,n=N%Mod;        for(j=1;j<=a[0]-1;++j)pro=pro*inv[j]%Mod*(n+a[0]-j)%Mod;        ans=(ans+f[i]*pro)%Mod;        //printf("%d(%d)*%I64d(%I64d,%d)=%I64d\n",f[i],i,pro,n+a[0]-1,a[0]-1,f[i]*pro%Mod);        for(i+=S,--N,--n;N>=0&&i<=sum;i+=S,--N,--n){            pro=pro*inver(n+a[0])%Mod*(n+1)%Mod;            ans=(ans+f[i]*pro)%Mod;            /*printf("%d(%d)*%I64d(%I64d,%d)=%I64d\n",f[i],i,pro,n+a[0]-1,a[0]-1,f[i]*pro%Mod);            cout<<n<<endl;*/        }        printf("%d\n",(ans+Mod)%Mod);    }}

我犯的错误:
①分解质因数时忘了考虑大于S的质因子。
②没注意到需要保证x1.

0 0
原创粉丝点击