题目描述
为了庆祝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
说明
【数据范围】
【时限1s,内存512M】
**
代码
--
**
/*
首先显然只需要考虑不超过 √n 的质因子对题目的影响。然后因为剩下的质因子只会出现至多一次,
因为对于n,质因数分解,最多只有一个质因子大于√n.再考虑这个大质数放哪个集合
我们记 f(S 1 , S 2 ) 表示两个集合中出现的质因子集合分别为S 1 , S 2 的方案数。
dp(j ,k, t) 为甲拿s1,乙拿s2,这个大质数放入t集合. t=0 or 1;
这样,转移的时候就只需考虑包含当前这个大于 n 的质因子的数放入那个集合中即可。
*/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
#define LL long long
int pri[8]={2,3,5,7,11,13,17,19},n,mod;
int f[500][500],dp[500][500][2];
int ans=0;
struct node{
int a,p; //a:这个数的质因数集合 p:大质数
bool operator < (const node & x) const
{ return p<x.p; }
}num[501];
void init(){
f[0][0]=1;
For(i,2,n){
int tmp=i;
For(j,0,7)
if(tmp%pri[j]==0){
while(tmp%pri[j]==0) tmp/=pri[j];
num[i].a|=(1<<j);
}
num[i].p=tmp; //不能被那八个质数除的部分为要求的大质数
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
scanf("%d%d",&n,&mod);
init(); // 预处理每个数的质因数集合与它的大质数
sort(num+2,num+n+1); //把质数相同的放一起讨论
For(i,2,n){
if(num[i].p==1 || num[i].p!=num[i-1].p){ //如果全在集合or换了一个质数,就是不同类.同类不能同时选
For(j,0,256) For(k,0,256)
dp[j][k][0]=dp[j][k][1]=f[j][k];
}
Rep(j,256,0) Rep(k,256,0){
if((num[i].a & k) == 0) // 如果该数集合与第二个人没交集,则可以放入第一个人集合
dp[j | num[i].a][k][1] = ((LL)dp[j | num[i].a][k][1]+ dp[j][k][1]) % mod;
if((num[i].a & j) == 0) // 同理放入第二个集合
dp[j][k | num[i].a][0] = ((LL)dp[j][k | num[i].a][0] + dp[j][k][0]) % mod;
}
if(num[i].p==1 || num[i].p!=num[i+1].p) //每次换类别时要改变方案情况
Rep(j,256,0) Rep(k,256,0)
f[j][k]=((LL)dp[j][k][0]+dp[j][k][1]-f[j][k])%mod; //这个数两人都不选时dp0 dp1都有包含
}
For(i,0,256) For(j,0,256)
if((i&j) == 0)
(ans+=f[i][j])%=mod;
printf("%d\n",(ans+mod)%mod);
return 0;
}