您的位置:首页 > 其它

NOI2015 寿司晚宴 状压DP

2017-04-03 20:06 267 查看
题目描述

为了庆祝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.考虑到选择一个数就等于选择了它的所有的质因子,于是想到将质因子状压,但是500还是太大。

2.因为n大于√n 的质因子只会有一个,于是我们可以把每个数按照大于√n的质因子进行分组(不存在的看作1)

3.接下来f[i][j]就表示第一个人选择质因子的情况为i,第二个人选择质因子的情况为j的方案数,再设dp[0][j][k]和dp[1][j][k]分别表示第一个人和第二个人选择完当前的这个数字后一二两个人选择质因子的情况分别是j,k时的方案数。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=510;
typedef pair<int,int> mp;
int n,p;
int prime[9]={0,2,3,5,7,11,13,17,19};
mp a[maxn];
int dp[2][1<<8][1<<8];
int f[1<<8][1<<8];
int main(){
scanf("%d%d",&n,&p);
for(int i=2;i<=n;i++){
int x=i;
for(int j=1;j<=8;j++){
while(x%prime[j]==0) a[i].second|=(1<<(j-1)),x/=prime[j];
}
a[i].first=x;
}
sort(a+2,a+1+n);
f[0][0]=1;
for(int i=2;i<=n;i++){
if(i==2 || a[i].first!=a[i-1].first || a[i].first==1){
memcpy(dp[0],f,sizeof(f));
memcpy(dp[1],f,sizeof(f));
}
for(int j=(1<<8)-1;j>=0;j--)
for(int k=(1<<8)-1;k>=0;k--){
if(!(k & a[i].second)) (dp[0][j|a[i].second][k]+=dp[0][j][k])%=p;
if(!(j & a[i].second)) (dp[1][j][k|a[i].second]+=dp[1][j][k])%=p;
}
if(i==n || a[i].first!=a[i+1].first || a[i].first==1){
for(int j=0;j<(1<<8);j++)
for(int k=0;k<(1<<8);k++)
f[j][k]=((dp[0][j][k]+dp[1][j][k]-f[j][k])%p+p)%p;
}
}
int ans=0;
for(int i=0;i<(1<<8);i++)
for(int j=0;j<(1<<8);j++)if(!(i & j)){
ans=(ans+f[i][j])%p;
}
printf("%d",ans);
return 0;
}


^_^
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp