[NOI2015]壽司晚宴
題目描述
為了慶祝NOI的成功開幕,主辦方為大家準備了一場壽司晚宴。小G和小W作為參加NOI的選手,也被邀請參加了壽司晚宴。
在晚宴上,主辦方為大家提供了n?1種不同的壽司,編號1,2,3,?,n-1,其中第種壽司的美味度為i+1(即壽司的美味度為從2到n)。
現在小G和小W希望每人選一些壽司種類來品嘗,他們規定一種品嘗方案為不和諧的當且僅當:小G品嘗的壽司種類中存在一種美味度為x的壽司,小W品嘗的壽司中存在一種美味度為y的壽司,而x與y不互質。
現在小G和小W希望統計一共有多少種和諧的品嘗壽司的方案(對給定的正整數p取模)。註意一個人可以不吃任何壽司。
輸入輸出格式
輸入格式:
從文件dinner.in中讀入數據。
輸入文件的第1行包含2個正整數n,p中間用單個空格隔開,表示共有n種壽司,最終和諧的方案數要對p取模。
輸出格式:
輸出到文件dinner.out中。
輸出一行包含1個整數,表示所求的方案模p的結果。
輸入輸出樣例
輸入樣例#1:3 10000輸出樣例#1:
9輸入樣例#2:
4 10000輸出樣例#2:
21輸入樣例#3:
100 100000000輸出樣例#3:
3107203
說明
【數據範圍】
【時限1s,內存512M】
首先,選一個數就相當於把他的質因子全部選了,那麽就先把每個數分解質因數.
因為sqrt(500)<23,所以只會有一個>=23的質因數和最多8個<23的質因數.
把<23的質因數狀壓,記為zt.還剩一個>23的質因數(沒有就是1),記為zs.
安裝zs排序,那麽每個zs相同的都看做一塊,這一塊要麽只能給A,要麽只能給B,或者一個都沒選.
設g[0/1][i][j]為兩個人狀態是i,j這一塊給A/B的方案數.
主要枚舉狀態要從大往小枚舉,避免重復統計.其實類似於01背包.
設f[i][j]為狀態為i,j的方案數.
每次處理完一塊用g來更新f.
f[i][j]=g[0][i][j]+g[1][i][j]-f[i][j].
重復統計了一個都沒選的,把他減掉.
1 #include<bits/stdc++.h> 2 using namespace std; 3 long long f[260][260],g[2][260][260]; 4 int pm[8]={2,3,5,7,11,13,17,19}; 5 struct data{ 6 int zt,zs; 7 }q[510]; 8 long long ans=0; 9 const int c=(1<<8); 10 inline bool cmp(const data &A,const data &B){ 11 return A.zs<B.zs; 12 } 13 int main(){ 14 int n,mod; 15 scanf("%d%d",&n,&mod); 16 for(int i=2;i<=n;i++){ 17 int xx=i; 18 for(int j=0;j<8;j++){ 19 if(xx%pm[j]==0)q[i].zt|=(1<<j); 20 while(xx%pm[j]==0) xx/=pm[j]; 21 } 22 q[i].zs=xx; 23 } 24 f[0][0]=1; 25 sort(q+2,q+n+1,cmp); 26 for(int i=2;i<=n;i++){ 27 if(i==2 || q[i-1].zs!=q[i].zs || q[i].zs==1) memcpy(g[0],f,sizeof(f)),memcpy(g[1],f,sizeof(f)); 28 int now=q[i].zt; 29 for(int j=c-1;j>=0;j--) 30 for(int k=c-1;k>=0;k--) 31 if(!(j&k)){ 32 if(!(now&k)) g[0][j|now][k]+=g[0][j][k],g[0][j|now][k]%=mod; 33 if(!(now&j)) g[1][j][k|now]+=g[1][j][k],g[1][j][k|now]%=mod; 34 } 35 if(i==n || q[i].zs!=q[i+1].zs || q[i].zs==1) 36 for(int j=c-1;j>=0;j--) 37 for(int k=c-1;k>=0;k--) 38 if(!(j&k)) f[j][k]=(g[0][j][k]+g[1][j][k]-f[j][k]+mod)%mod; 39 } 40 for(int i=0;i<c;i++) 41 for(int j=0;j<c;j++) 42 if(!(i&j)) ans+=f[i][j],ans%=mod; 43 printf("%lld",ans%mod); 44 return 0; 45 }
usingnamespacestd; longlong f[260][260],g[2][260][260]; int pm[8]={2,3,5,7,11,13,17,19}; struct data{ int zt,zs; }q[510]; longlong ans=0; constint c=(1<<8); inline bool cmp(const data &A,const data &B){ return A.zs<B.zs; } int main(){ int n,mod; scanf("%d%d",&n,&mod); for(int i=2;i<=n;i++){ int xx=i; for(int j=0;j<8;j++){ if(xx%pm[j]==0)q[i].zt|=(1<<j); while(xx%pm[j]==0) xx/=pm[j]; } q[i].zs=xx; } f[0][0]=1; sort(q+2,q+n+1,cmp); for(int i=2;i<=n;i++){ if(i==2 || q[i-1].zs!=q[i].zs || q[i].zs==1) memcpy(g[0],f,sizeof(f)),memcpy(g[1],f,sizeof(f)); int now=q[i].zt; for(int j=c-1;j>=0;j--) for(int k=c-1;k>=0;k--) if(!(j&k)){ if(!(now&k)) g[0][j|now][k]+=g[0][j][k],g[0][j|now][k]%=mod; if(!(now&j)) g[1][j][k|now]+=g[1][j][k],g[1][j][k|now]%=mod; } if(i==n || q[i].zs!=q[i+1].zs || q[i].zs==1) for(int j=c-1;j>=0;j--) for(int k=c-1;k>=0;k--) if(!(j&k)) f[j][k]=(g[0][j][k]+g[1][j][k]-f[j][k]+mod)%mod; } for(int i=0;i<c;i++) for(int j=0;j<c;j++) if(!(i&j)) ans+=f[i][j],ans%=mod; printf("%lld",ans%mod); return0; }
[NOI2015]壽司晚宴