爲了慶祝 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;
}