[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 }

 

posted @ 2017-07-19 09:35  Z-Y-Y-S  阅读(273)  评论(0编辑  收藏  举报