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

[NOI2005]壽司晚宴

code str 希望 素數 保存 題目 給定 情況 註意

題目描述

為了慶祝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
題解:
小於√500的素數有8個,對於題意,可以理解為兩人不能有同一素數倍數的壽司
比如選了6,相當於選了2,3,則;另一人不能選2,3的倍數
用8為二進制數來保存情況,狀壓dp
f[j][k]表示小G為j小W為k的方案數,p[1][j][k]表示小G選,p[2][j][k]表示小w選
註意一個數可能有大於√500的因數,但顯然只能有一個,記錄下為ki,如果ki相同也不能選
轉移後f[j][k]=p[1][j][k]+p[2][j][k]-f[j][k]
減去f[j][k]是因為p[1],p[2]都算了f[j][k],所以減去
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 struct Node
 7 {
 8     int se,ki;
 9 } s[1201];
10 int prime[8]= {2,3,5,7,11,13,17,19};
11 int n;
12 int p[3][601][601],f[601][601],Mod,ans;
13 bool cmp(Node a,Node b)
14 { 15 if (a.ki!=b.ki) return a.ki<b.ki; 16 else return a.se<b.se; 17 } 18 int main() 19 {int i,j,k; 20 //freopen("1.out","w",stdout); 21 cin>>n>>Mod; 22 for (int i=1; i<=n; i++) 23 { 24 int tmp; 25 tmp=i; 26 //cout<<i<<endl; 27 for (int j=0; j<8; j++) 28 { 29 if (tmp%prime[j]==0) 30 { 31 s[i].se|=1<<j; 32 while (tmp%prime[j]==0) tmp/=prime[j]; 33 } 34 } 35 s[i].ki=tmp; 36 } 37 sort(s+2,s+n+1,cmp); 38 f[0][0]=1; 39 for (int i=2; i<=n; i++) 40 { 41 if (i==2||s[i].ki==1||s[i].ki!=s[i-1].ki) 42 { 43 for (int j=0; j<=255; j++) 44 { 45 for (int k=0; k<=255; k++) 46 { 47 p[1][j][k]=f[j][k]; 48 p[2][j][k]=f[j][k]; 49 } 50 } 51 } 52 for (int j=255; j>=0; j--) 53 { 54 for (int k=255; k>=0; k--) 55 { 56 if ((k&s[i].se)==0) p[1][j|s[i].se][k]=(p[1][j|s[i].se][k]+p[1][j][k])%Mod; 57 if ((j&s[i].se)==0) p[2][j][k|s[i].se]=(p[2][j][k|s[i].se]+p[2][j][k])%Mod; 58 } 59 } 60 if (i==n||s[i].ki==1||s[i].ki!=s[i+1].ki) 61 { 62 for (int j=0; j<=255; j++) 63 { 64 for (int k=0; k<=255; k++) 65 { 66 f[j][k]=((p[1][j][k]+p[2][j][k]-f[j][k])%Mod+Mod)%Mod; 67 } 68 } 69 } 70 } 71 for (int i=0; i<=255; i++) 72 { 73 for (int j=0; j<=255; j++) 74 { 75 if ((i&j)==0) 76 { 77 //printf("%d %d %d\n",f[i][j],i,j); 78 ans=(ans+f[i][j])%Mod; 79 } 80 } 81 } 82 cout<<ans; 83 }

[NOI2005]壽司晚宴