4197: [Noi2015]寿司晚宴
Time Limit: 10 Sec Memory Limit: 512 MBDescription
为了庆祝 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
题解:
前8个质因子,状压
这n<=500的数都最多包含一个大于根号n的质因子
跑01背包
#include<bits/stdc++.h> using namespace std; #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; typedef unsigned long long ULL; const long long INF = 1e18+1LL; const double pi = acos(-1.0); const int N=2000+20,M=1e6+10,inf=2147483647; int p[] = {2,3,5,7,11,13,17,19}; int dp[2][(1<<8)+10][(1<<8)+10],pd[2][(1<<8)+10][(1<<8)+10],n,P,f[N],has[(1<<8)+10][(1<<8)+10]; vector<int > fi,se[N]; int main() { scanf("%d%d",&n,&P); for(int i = 2; i <= n; ++i) { int tmp = i,now = 0; for(int j = 0; j < 8; ++j) while(tmp%p[j] == 0) now|=(1<<j),tmp/=p[j]; if(tmp == 1) f[i] = now,fi.push_back(i); else f[i] = now,se[tmp].push_back(i); } int now = 0; dp[0][0][0] = 1; for(int g = 0; g < fi.size(); ++g) { int u = fi[g]; now ^= 1; memset(dp[now],0,sizeof(dp[now])); for(int i = 0; i < (1<<8); ++i) for(int j = 0; j < (1<<8); ++j) { if((j&f[u])==0) dp[now][i|f[u]][j] += dp[now^1][i][j]%P,dp[now][i|f[u]][j]%=P; if((i&f[u])==0) dp[now][i][j|f[u]] += dp[now^1][i][j]%P,dp[now][i][j|f[u]]%=P; dp[now][i][j] += dp[now^1][i][j]%P,dp[now][i][j]%=P; } } for(int S = 2; S <= n; ++S) { if(se[S].size() == 0) continue; int tmp = now; for(int i = 0; i < (1<<8); ++i) for(int j = 0; j < (1<<8); ++j) has[i][j] = pd[tmp][i][j] = dp[now][i][j]; for(int g = 0; g < se[S].size(); ++g) { now ^= 1; memset(dp[now],0,sizeof(dp[now])); for(int i = 0; i < (1<<8); ++i) for(int j = 0; j < (1<<8); ++j) { int u = se[S][g]; if((i&f[u])==0) dp[now][i][j|f[u]] += dp[now^1][i][j]%P,dp[now][i][j|f[u]]%=P; dp[now][i][j] += dp[now^1][i][j]%P,dp[now][i][j]%=P; } } for(int g = 0; g < se[S].size(); ++g) { tmp ^= 1; memset(pd[tmp],0,sizeof(pd[tmp])); for(int i = 0; i < (1<<8); ++i) for(int j = 0; j < (1<<8); ++j) { int u = se[S][g]; if((j&f[u])==0) pd[tmp][i|f[u]][j] += pd[tmp^1][i][j]%P,pd[tmp][i|f[u]][j]%=P; pd[tmp][i][j] += pd[tmp^1][i][j]%P,pd[tmp][i][j]%=P; } } for(int i = 0; i < (1<<8); ++i) for(int j = 0; j < (1<<8); ++j) dp[now][i][j] += ((pd[tmp][i][j] - has[i][j])%P+P)%P,dp[now][i][j] %= P; } int ans = 0; for(int i = 0; i < (1<<8); ++i) for(int j = 0; j < (1<<8); ++j) if((i&j) == 0)ans += dp[now][i][j],ans %= P; printf("%d ",ans); return 0; }