題意:http://www.lydsy.com/JudgeOnline/problem.php?id=4772
sol :這個題卡了我一整天QAQ
出題人簡直喪心病狂,卡內存+卡常數QAQ
題意就是,給你一個整數,讓你求所有整數划分的方案數的價值和,價值是個函數
長成這個樣子:
∑划分方案數
然后就是,考慮枚舉pi和pj,如何算這個二元組在整數划分中出現的次數
記sum[i]為將i進行整數划分的方案數(實際操作時為避免數組下標為負所以將sum反向)
sum[0]=1; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==1||j==1) f[i][j]=1; else if(i==j) f[i][j]=(f[i][j-1]+1)%p; else if(i<j) f[i][j]=f[i][j-1]; else f[i][j]=(f[i-j][j]+f[i][j-1])%p; } sum[i]=f[i][i]; }
當pi!=pj的時候,枚舉pi和pj出現的次數muli,mulj,那么答案即為ans[pi][pj]+=sum[n-pi*muli-pj*mulj]
而當pi=pj時,同樣枚舉pi出現的次數,我們要考慮兩兩組合的方案數
即ans[pi][pi]+=muli*(muli-1)/2*(sum[muli*pi]-sum[(muli+1)*pi])
然后我到這就不會了QAQ,於是去請教了Nbc和Claris,%%%
Nbc表示這個題就是個暴力隨便搞搞就行了......我:
Claris表示其實這個g是個積性函數......我:
好了這個題可以做了QAQ
我們考慮g(n)在n為質數的情況下的值為2n-2,所以直接預處理線性篩一發g(x)就行了QAQ
然后對於那個F(i,j)我們可以預處理一發gcd和pow就可以O(1)做了
於是我們的做法就是,枚舉不相等的i和j,統計答案
for(int i=1;i<=n;i++) for(int j=i+1;j<=n-i;j++) for(int muli=1;muli*i+j<=n;muli++) for(int mulj=1;mulj*j+muli*i<=n;mulj++) ans+=g[a[F(i,j)]]*sum[muli*i+mulj*j]%p,ans%=p;
然后再枚舉相等的i和j,統計答案
for(int i=1;i<=n;i++) for(int muli=1;muli*i<=n;muli++) ans=(ans+g[a[F(i,i)]]*muli*(muli-1)/2*(sum[muli*i]-sum[(muli+1)*i]+p))%p;
然后我們就愉悅的發現他0ms TLE了
哦....原來是define int long long炸內存了啊QAQ
簡單的改了改然后交上去,發現他又偷♂稅的T掉了......
我們發現在統計不相等的i和j時的取模操作太多了QAQ
於是我們可以手動實現一發取模操作...然而我並不會乘法取模,怎么辦呢?
我們發現乘法取模是因為乘了一個g[],然而F(i,j)的范圍只有1e5,奧妙重重
考慮開一個數組Cnt記錄F的每個值的訪問次數,這樣的話在后面一次性統計即可
for(int i=1;i<=n;i++) for(int j=i+1;j<=n-i;j++) for(int muli=1;muli*i+j<=n;muli++) for(int mulj=1;mulj*j+muli*i<=n;mulj++) mod(Cnt[F(i,j)],sum[muli*i+mulj*j]); for(int i=0;i<K;i++) ans+=1LL*g[a[i]]*Cnt[i]%p,ans%=p;
於是這道題就可以切掉了QwQ
附上完整代碼
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int p=1e9+7; const int Mx1=2010; const int Mx2=1e7+10; int tp,n,K,a[Mx2],sum[Mx1],f[Mx1][Mx1],gcd[Mx1][Mx1],mul[Mx1][Mx1]; int cnt,ans,pri[Mx2],tmp[Mx2],g[Mx2],b[Mx1]; bool jud[Mx2]; inline void pre() { sum[n]=1; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==1||j==1) f[i][j]=1; else if(i==j) f[i][j]=(f[i][j-1]+1)%p; else if(i<j) f[i][j]=f[i][j-1]; else f[i][j]=(f[i-j][j]+f[i][j-1])%p; } sum[n-i]=f[i][i]; } g[0]=0,g[1]=1; for(int i=2;i<=1e7;i++) { if(!jud[i]) pri[++cnt]=tmp[i]=i,g[i]=(2*i-2)%p; for(int j=1;j<=cnt&&i*pri[j]<=1e7;j++) { jud[i*pri[j]]=1; if(i%pri[j]) tmp[i*pri[j]]=pri[j], g[i*pri[j]]=g[i]*g[pri[j]]%p; else { tmp[i*pri[j]]=tmp[i]*pri[j]; if(tmp[i]!=i) g[i*pri[j]]=1LL*g[i/tmp[i]]*g[tmp[i]*pri[j]]%p; else g[i*pri[j]]=(1LL*g[i]*pri[j]+i*pri[j]-i)%p; break; } } } for(int i=1;i<=n;i++) gcd[i][0]=gcd[0][i]=gcd[i][i]=i,gcd[1][i]=gcd[i][1]=1; for(int i=2;i<=n;i++) for(int j=2;j<=i;j++) { if(!gcd[i][j]) gcd[i][j]=gcd[j][i-j]; gcd[j][i]=gcd[i][j]; } for(int i=1;i<=n;i++) { mul[i][0]=1; for(int j=1;j<=n;j++) mul[i][j]=(1LL*mul[i][j-1]*i)%K; } } inline int F(int pi,int pj) { if(tp==1) return 1%K; if(tp==2) return (gcd[pi][pj])%K; if(tp==3) return (mul[pi][pj]+mul[pj][pi]+(pi^pj))%K; } inline void mod(int &x,const int &y){ x+=y; if (x>=p) x-=p; } int Cnt[Mx2]; int main() { scanf("%d%d%d",&tp,&n,&K); for(int i=0;i<K;i++) scanf("%d",&a[i]); pre(); for(int i=1;i<=n;i++) for(int j=i+1;j<=n-i;j++) for(int muli=1;muli*i+j<=n;muli++) for(int mulj=1;mulj*j+muli*i<=n;mulj++) mod(Cnt[F(i,j)],sum[muli*i+mulj*j]); for(int i=0;i<K;i++) ans+=1LL*g[a[i]]*Cnt[i]%p,ans%=p; for(int i=1;i<=n;i++) { for(int muli=1;muli*i<=n;muli++) { int Tmp=1LL*muli*(muli-1)/2*(sum[muli*i]-sum[(muli+1)*i]+p)%p; mod(ans,1LL*g[a[F(i,i)]]*Tmp%p); } } cout<<ans<<endl; return 0; }