bzoj4197 [Noi2015]寿司晚宴
来源:互联网 发布:物流企业软件供应商 编辑:程序博客网 时间:2024/04/20 10:19
【题意】
给出2~n共(n-1)个数,每个数可以放入A集合、放入B集合或不放,满足A集合任意一个数与B集合任意一个数均互质,求方案数。
【数据范围】
n<=500
【思路】
好题
核心思想:将质数按sqrt(n)分成两类!
[1]<=sqrt(n)的质数<=8个
[2]>sqrt(n)的质数有很多,但是2~n中的每个数分解质因数后这类质因子最多有1个
枚举2~n中每个数,若i中存在[2]类质因子x(最多1个),把i归为x那一组
将A、B集合的数分解质因数,在一种合法方案中,A、B集合的质因子交集为空
对[1]质数状压dp,f[s1][s2]=A集合中质因子存在状态为s1,B集合中质因子存在状态为s2,合法方案数
初始f[0][0]=1
对于没有分组的2~n中的数,直接O(1)转移
枚举每一组,则这一组的所有数要么均不能加入A集合,要么均不能加入B集合,分这两种情况对这一组整体DP,将两种情况答案相加,注意所有数均不加入的情况被统计了2次,需要减掉1次(即减掉f初值)
由于A、B集合元素交集为空,故也可以使用3^8状压
【时间复杂度】
O(n*4^8)
#include<cstdio>#include<cstring>#include<algorithm>#define N 510using namespace std; int n, mod, flag[N], p[N], l, sum, L[N], w[N], map[N][N], f[260][260], g[260][260], l1,a[10], bin[20], now, ans, f1[260][260], f2[260][260], g1[260][260], g2[260][260]; void prev(){ memset(flag, 0, sizeof(flag)); l=0; for(int i=2; i<=n; i++){ if(!flag[i])p[++l]=i; for(int j=1; j<=l&&i*p[j]<=n; j++){ flag[i*p[j]]=1; if(i%p[j]==0)break; } }} int main(){ scanf("%d%d", &n, &mod); bin[0]=1; for(int i=1; i<=10; i++)bin[i]=bin[i-1]<<1; prev(); sum=0; for(int i=1; i<=l; i++)if(p[i]*p[i]<=500)sum++; for(int i=1; i<=l-sum; i++){w[i]=p[i+sum]; L[i]=0;} L[0]=0; memset(flag, 0, sizeof(flag)); for(int i=2; i<=n; i++) for(int j=1; j<=l-sum; j++)if(i%w[j]==0){map[j][++L[j]]=i; flag[i]=j;} for(int i=2; i<=n; i++)if(!flag[i])map[0][++L[0]]=i; f[0][0]=1; for(int i=1; i<=L[0]; i++){ now=0; for(int j=1; j<=sum; j++)if(map[0][i]%p[j]==0)now+=bin[j-1]; memset(g, 0, sizeof(g)); for(int j=0; j<=bin[sum]-1; j++) for(int k=0; k<=bin[sum]-1; k++)if(f[j][k]){ g[j][k]=(g[j][k]+f[j][k])%mod; g[j|now][k]=(g[j|now][k]+f[j][k])%mod; g[j][k|now]=(g[j][k|now]+f[j][k])%mod; } for(int j=0; j<=bin[sum]-1; j++) for(int k=0; k<=bin[sum]-1; k++)if(j&k)g[j][k]=0; memcpy(f, g, sizeof(f)); } for(int i=1; i<=l-sum; i++){ memcpy(f1, f, sizeof(f1)); memcpy(f2, f, sizeof(f2)); for(int j=1; j<=L[i]; j++){ memset(g1, 0, sizeof(g1)); memset(g2, 0, sizeof(g2)); now=0; for(int k=1; k<=sum; k++)if(map[i][j]%p[k]==0)now+=bin[k-1]; for(int k=0; k<=bin[sum]-1; k++) for(int m=0; m<=bin[sum]-1; m++){ g1[k][m]=(g1[k][m]+f1[k][m])%mod; g1[k|now][m]=(g1[k|now][m]+f1[k][m])%mod; g2[k][m]=(g2[k][m]+f2[k][m])%mod; g2[k][m|now]=(g2[k][m|now]+f2[k][m])%mod; } for(int k=0; k<=bin[sum]-1; k++) for(int m=0; m<=bin[sum]-1; m++)if(k&m)g1[k][m]=g2[k][m]=0; memcpy(f1, g1, sizeof(f1)); memcpy(f2, g2, sizeof(f2)); } memset(g, 0, sizeof(g)); for(int j=0; j<=bin[sum]-1; j++) for(int k=0; k<=bin[sum]-1; k++){ g[j][k]=(f1[j][k]+f2[j][k]-f[j][k])%mod; if(g[j][k]<0)g[j][k]+=mod; } for(int j=0; j<=bin[sum]-1; j++) for(int k=0; k<=bin[sum]-1; k++)if(j&k)g[j][k]=0; memcpy(f, g, sizeof(f)); } ans=0; for(int i=0; i<=bin[sum]-1; i++) for(int j=0; j<=bin[sum]-1; j++)ans=(ans+f[i][j])%mod; printf("%d", ans);}
0 0
- BZOJ4197 [Noi2015]寿司晚宴
- bzoj4197 [Noi2015]寿司晚宴
- 【bzoj4197】[Noi2015]寿司晚宴
- Bzoj4197: [Noi2015]寿司晚宴
- 【bzoj4197】【NOI2015】寿司晚宴
- 【bzoj4197】[Noi2015]寿司晚宴 dp
- 【bzoj4197】[Noi2015]寿司晚宴 状压DP
- 【BZOJ4197】[Noi2015]寿司晚宴【状压DP】【背包】
- [NOI2015][BZOJ4197][状压DP]寿司晚宴
- bzoj4197[Noi2015]寿司晚宴 [状压DP]
- bzoj4197 [NOI2015] [状压dp] 寿司晚宴
- BZOJ4197: [Noi2015]寿司晚宴 状压DP
- 【NOI2015】【bzoj4197】【状压DP】【滚动数组】寿司晚宴
- 4197: [Noi2015]寿司晚宴
- 4197: [Noi2015]寿司晚宴
- 【NOI2015】【寿司晚宴】【状压DP】
- bzoj 4197: [Noi2015]寿司晚宴
- BZOJ 4197 Noi2015 寿司晚宴
- Android编程权威指南(第二版)学习笔记(十九)—— 第19章 使用 SoundPool 播放音频
- 剪裁头像裁剪遇到关于小米华为适配问题的解决
- PAT---B1036. 跟奥巴马一起编程(15)
- Windows驱动程序学习步骤
- 单片机学习
- bzoj4197 [Noi2015]寿司晚宴
- PAT---B1027. 打印沙漏(20)
- Nginx服务器安装和使用
- STL容器之优先队列
- linux 下 python 环境搭建
- 记录一些有用的东西-1
- Sublime快捷使用(三)
- Java-异常
- JAVA之equals