[BZOJ4197][Noi2015]寿司晚宴

4197: [Noi2015]寿司晚宴

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 412  Solved: 279
[Submit][Status][Discuss]

Description

为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴。小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴。

在晚宴上,主办方为大家提供了 n−1 种不同的寿司,编号 1,2,3,…,n−1,其中第 i 种寿司的美味度为 i+1 (即寿司的美味度为从 2 到 n)。
现在小 G 和小 W 希望每人选一些寿司种类来品尝,他们规定一种品尝方案为不和谐的当且仅当:小 G 品尝的寿司种类中存在一种美味度为 x 的寿司,小 W 品尝的寿司中存在一种美味度为 y 的寿司,而 x 与 y 不互质。
现在小 G 和小 W 希望统计一共有多少种和谐的品尝寿司的方案(对给定的正整数 p 取模)。注意一个人可以不吃任何寿司。
 

Input

输入文件的第 1 行包含 2 个正整数 n,p,中间用单个空格隔开,表示共有 n 种寿司,最终和谐的方案数要对 p 取模。

 

Output

输出一行包含 1 个整数,表示所求的方案模 p 的结果。

 

Sample Input

3 10000

Sample Output

9

HINT

 2≤n≤500


0<p≤1000000000

Source

 
[Submit][Status][Discuss]


HOME Back

30分做法:

考虑对于每个质数状压DP,f[i][j]表示第一个人选取集合为i,第二个人选取集合为j的方案数。比较简单的DP。

100分做法:

对于大于$sqrt n$的质数,每个数至多包含1个这样的因子,所以可以对小于$sqrt n$的质数,这样的数至多有8个。

对于每个数,对其大于$sqrt n$的质因子分类,分别做DP即可。dp[i][j][2]表示第一个人选取集合为i,第二个人选取集合为j,质因子分给第i个人的方案数。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define ll long long
 4 using namespace std;
 5 int f[1<<8][1<<8],n,mod,dp[1<<8][1<<8][2];
 6 int prime[]={2,3,5,7,11,13,17,19},tot,ans;
 7 struct node{int p,S;}a[505];
 8 bool operator<(node x,node y){return x.p<y.p;}
 9 inline void solve(int x)
10 {
11     int now=0;
12     for(int i=0;i<8;i++)
13     if(!(x%prime[i]))
14     {
15         now|=1<<i;
16         while(!(x%prime[i]))x/=prime[i];
17     }
18     a[++tot]=(node){x,now};
19 }
20 int main()
21 {
22     scanf("%d%d",&n,&mod);
23     f[0][0]=1;
24     for(int i=2;i<=n;i++)solve(i);
25     sort(a+1,a+tot+1);
26     for(int l=1,r;l<=tot;l=r+1)
27     {
28         for(r=l;r<tot&&a[r+1].p==a[r].p&&a[r].p!=1;r++);
29         for(int i=0;i<256;i++)
30         for(int j=0;j<256;j++)
31         dp[i][j][0]=dp[i][j][1]=f[i][j];
32         for(int k=l;k<=r;k++)
33         {
34             for(int i=255;~i;i--)
35             {
36                 int now=255-i;
37                 for(int j=now;;j=(j-1)&now)
38                 {
39                     if((a[k].S&j)==0)
40                     {
41                         dp[i|a[k].S][j][0]+=dp[i][j][0];
42                         if(dp[i|a[k].S][j][0]>=mod)
43                         dp[i|a[k].S][j][0]-=mod;
44                     }
45                     if((a[k].S&i)==0)
46                     {
47                         dp[i][j|a[k].S][1]+=dp[i][j][1];
48                         if(dp[i][j|a[k].S][1]>=mod)
49                         dp[i][j|a[k].S][1]-=mod;
50                     }
51                     if(!j)break;
52                 }
53             }
54         }
55         for(int i=0;i<256;i++)
56         for(int j=0;j<256;j++)
57         {
58             f[i][j]=dp[i][j][0]+dp[i][j][1]-f[i][j];
59             if(f[i][j]>=mod)f[i][j]-=mod;
60             if(f[i][j]<0)f[i][j]+=mod;
61         }
62     }
63     for(int i=0;i<256;i++)
64     {
65         int now=255-i;
66         for(int j=now;;j=(j-1)&now)
67         {
68             ans+=f[i][j];
69             if(ans>=mod)ans-=mod;
70             if(!j)break;
71         }
72     }
73     printf("%d
",ans);
74 }
View Code
原文地址:https://www.cnblogs.com/xuruifan/p/5577328.html