为了庆祝 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 取模)。注意一个人可以不吃任何寿司。
输入格式
输入文件的第 1 行包含 2 个正整数 n,p ,中间用单个空格隔开,表示共有 n 种寿司,最终和谐的方案数要对 p 取模。
输出格式
输出一行包含 1 个整数,表示所求的方案模 p 的结果。
样例一
input
3 10000
output
9
样例二
input
4 10000
output
21
样例三
input
100 100000000
output
3107203
限制与约定
测试点编号 | n 的规模 | 约定 |
---|---|---|
1 | 2≤n≤30 | 0<p≤1000000000 |
2 | ||
3 | ||
4 | 2≤n≤100 | |
5 | ||
6 | 2≤n≤200 | |
7 | ||
8 | 2≤n≤500 | |
9 | ||
10 |
时间限制: 1s
空间限制: 512MB
下载
样例数据下载
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~状压DP~
可以发现n<=500,质因子最多有8个,记录每个数对于这8个质因子的包含状态,再记录下另一个>sqrt(n)的质因子,状压DP即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;const int pri[]={2,3,5,7,11,13,17,19};int n,mod,x,f[301][301],g[2][301][301],ans;struct node{int pri,els;bool operator < (const node&u) const{return pri==u.pri ? els<u.els:pri<u.pri;}
}a[501];int main()
{scanf("%d%d",&n,&mod);for(int i=1;i<=n;i++){x=i;for(int j=0;j<8;j++)if(!(x%pri[j])){while(!(x%pri[j])) x/=pri[j];a[i].els|=1<<j;}a[i].pri=x;}sort(a+2,a+n+1);f[0][0]=1;for(int i=2;i<=n;i++){if(i==2 || a[i].pri==1 || a[i].pri!=a[i-1].pri){memcpy(g[0],f,sizeof(g[0]));memcpy(g[1],f,sizeof(g[1]));}for(int j=255;~j;j--)for(int k=255;~k;k--){if(!(k&a[i].els)) g[0][j|a[i].els][k]=(g[0][j][k]+g[0][j|a[i].els][k])%mod;if(!(j&a[i].els)) g[1][j][k|a[i].els]=(g[1][j][k]+g[1][j][k|a[i].els])%mod;}if(i==n || a[i].pri==1 || a[i].pri!=a[i+1].pri){for(int j=0;j<=255;j++)for(int k=0;k<=255;k++)f[j][k]=((g[0][j][k]+g[1][j][k]-f[j][k])%mod+mod)%mod;}}for(int i=0;i<=255;i++)for(int j=0;j<=255;j++) if(!(i&j)) ans=(ans+f[i][j])%mod;printf("%d\n",ans);return 0;
}