1. 程式人生 > >[NOI2015]壽司晚宴

[NOI2015]壽司晚宴

oid 包含 new using lib 一場 tle load ner

題目描述

為了慶祝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 }

#include<bits/stdc++.h>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]壽司晚宴