[NOI2005]寿司晚宴
Posted Z-Y-Y-S
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOI2005]寿司晚宴相关的知识,希望对你有一定的参考价值。
题目描述
为了庆祝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]寿司晚宴的主要内容,如果未能解决你的问题,请参考以下文章