【bzoj4197】[Noi2015]寿司晚宴 分解质因数+状态压缩dp
题目描述
为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴。小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴。
输入
输入文件的第 1 行包含 2 个正整数 n,p,中间用单个空格隔开,表示共有 n 种寿司,最终和谐的方案数要对 p 取模。
输出
输出一行包含 1 个整数,表示所求的方案模 p 的结果。
样例输入
3 10000
样例输出
9
题解
分解质因数+状态压缩dp
对于这种题肯定想到使用状压dp来解决,即设f[v1][v2]表示甲选质数的状态为v1,乙选质数的状态为v2的方案数。
但是这样状态数会爆炸。
考虑:大于$\sqrt{500}$的质数在某数中最多只会出现一次,而小于等于$\sqrt{500}$的质数只有8个。
所以我们只需要记录8个小质数的状态,对于大质数单独处理。
对于每个2~n的数,把它们分解质因数,并记录它们包含小质数的状态和包含的大质数(没有则为0)。
然后把每个数按照大质数的大小排序,这样每个大质数出现的位置是一段连续的区间。
对于每个大质数对应的区间,设$g[i][j]$表示乙不选这个大质数,甲、乙状态分别为i、j的方案数;$h[i][j]$表示甲不选这个大质数,甲、乙状态分别为i、j的方案数。
那么初始$g[i][j]=h[i][j]=f[i][j]$,转移时$g[i|v][j]+=g[i][j]\ \ (v\&j=0)$,h同理。
更新完g和h后更新f为$f[i][j]=g[i][j]+h[i][j]-f[i][j]$,因为两者都不选的情况算了2次。
对于不包含大质数的数,拿出来单独处理即可。
注意一下循环顺序,不要重复更新,必要时可以记录原状态(不包含大质数的数的处理方法中,f数组可能在使用前已经更新,所以这里再使用g数组记录原来的f)
时间复杂度$O(500·2^{16})$
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 520
using namespace std;
const int pos[] = {0 , 0 , 0 , 1 , 0 , 2 , 0 , 3 , 0 , 0 , 0 , 4 , 0 , 5 , 0 , 0 , 0 , 6 , 0 , 7};
struct data
{
int val , mp;
bool operator<(const data a)const {return mp > a.mp;}
}a[N];
int f[N][N] , g[N][N] , h[N][N];
int main()
{
int n , p , i , j , k , l , last , t , ans = 0;
scanf("%d%d" , &n , &p);
for(i = 2 ; i <= n ; i ++ )
{
for(j = 2 , t = i ; j * j <= t ; j ++ )
{
if(t % j == 0)
{
a[i - 1].val |= (1 << pos[j]);
while(t % j == 0) t /= j;
}
}
if(t > 1)
{
if(t > 19) a[i - 1].mp = t;
else a[i - 1].val |= (1 << pos[t]);
}
}
sort(a + 1 , a + n);
f[0][0] = 1;
for(i = last = 1 ; i < n ; i = last + 1)
{
if(a[i].mp)
{
while(last < n - 1 && a[last + 1].mp == a[i].mp) last ++ ;
for(j = 0 ; j < 256 ; j ++ )
for(k = 0 ; k < 256 ; k ++ )
g[j][k] = h[j][k] = f[j][k];
for(j = i ; j <= last ; j ++ )
for(k = 255 ; ~k ; k -- )
for(l = 255 ; ~l ; l -- )
if(!(k & l) && !(a[j].val & l))
g[k | a[j].val][l] = (g[k | a[j].val][l] + g[k][l]) % p , h[l][k | a[j].val] = (h[l][k | a[j].val] + h[l][k]) % p;
for(j = 0 ; j < 256 ; j ++ )
for(k = 0 ; k < 256 ; k ++ )
f[j][k] = ((g[j][k] + h[j][k] - f[j][k]) % p + p) % p;
}
else
{
last = i;
for(j = 0 ; j < 256 ; j ++ )
for(k = 0 ; k < 256 ; k ++ )
g[j][k] = f[j][k];
for(j = 255 ; ~j ; j -- )
for(k = 255 ; ~k ; k -- )
if(!(j & k) && !(a[i].val & k))
f[j | a[i].val][k] = (f[j | a[i].val][k] + g[j][k]) % p , f[k][j | a[i].val] = (f[k][j | a[i].val] + g[j][k]) % p;
}
}
for(i = 0 ; i < 256 ; i ++ )
for(j = 0 ; j < 256 ; j ++ )
if(!(i & j) && f[i][j])
ans = (ans + f[i][j]) % p;
printf("%d\n" , ans);
return 0;
}
【bzoj4197】[Noi2015]寿司晚宴 分解质因数+状态压缩dp的更多相关文章
- [UOJ#129][BZOJ4197][Noi2015]寿司晚宴
[UOJ#129][BZOJ4197][Noi2015]寿司晚宴 试题描述 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司 ...
- [BZOJ4197][Noi2015]寿司晚宴
4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 412 Solved: 279[Submit][Status] ...
- bzoj4197 [Noi2015]寿司晚宴——状压DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4197 首先,两个人选的数都互质可以看作是一个人选了一个数,就相当于选了一个质因数集合,另一个 ...
- BZOJ4197 [Noi2015]寿司晚宴 【状压dp】
题目链接 BZOJ4197 题解 两个人选的数都互质,意味着两个人选择了没有交集的质因子集合 容易想到将两个人所选的质因子集合作为状态\(dp\) \(n\)以内质数很多,但容易发现\(\sqrt{n ...
- UOJ129 NOI2015 寿司晚宴 数论、状压DP
传送门 数论题\(n \leq 500\)肯定是什么暴力算法-- 注意到每一个数\(> \sqrt{n}\)的因子最多只有一个,这意味着\(> \sqrt{n}\)的因子之间是独立的,而只 ...
- 【BZOJ4197】[Noi2015]寿司晚宴 状压DP+分解质因数
[BZOJ4197][Noi2015]寿司晚宴 Description 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴 ...
- BZOJ_4197_[Noi2015]寿司晚宴_状态压缩动态规划
BZOJ_4197_[Noi2015]寿司晚宴_状态压缩动态规划 Description 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被 ...
- BZOJ 4197: [Noi2015]寿司晚宴 状态压缩 + 01背包
4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec Memory Limit: 512 MB Description 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿 ...
- NOI2015 寿司晚宴
今年NOI确实是在下输了.最近想把当时不会做的题都写一下. 题意 从2到n(500)这些数字中,选若干分给A,若干分给B,满足不存在:A的某个数和B的某个数的GCD不等于1. 对于寿司晚宴这题,标准解 ...
随机推荐
- MFC双缓冲解决图象闪烁[转]
转载网上找到的一篇双缓冲的文章,很好用.http://www.cnblogs.com/piggger/archive/2009/05/02/1447917.html__________________ ...
- mac系统连接Android手机
1. 打开终端,输入:system_profiler SPUSBDataType,查看Mac系统所有USB设备信息,找到相应的厂商Vender ID 2.输入echo "Vender ID& ...
- linux下使用OpenCV的一些问题
完整正确的代码如下: import cv2 import numpy as np image = cv2.imread('Pictures/a.png') cv2.imshow('original_i ...
- python中的循环语句-01
接触python已经一周时间,下面针对这一周python学习的情况做一梳理: 1)单行注释,使用一个#:多行注释,使用三个单引号(或者三个双引号)如: name = input("name: ...
- iview 验证 trigger: 'blur,change', 同时加两个,省的每次还想input 还是 select
iview 验证 trigger: 'blur,change', 同时加两个,省的每次还想input 还是 select dataRuleValidate: { name: [{ required: ...
- vue 实现走马灯效果
Part.1 问题 在写一个H5页面时遇到一个需求,头部公告需要滚动变换,需要实现一个走马灯效果 Part.2 实现 我的做法:利用 定时器 + CSS3 变换公告数组的顺序 从而实现走马灯效果 ...
- mac 上node.js环境的安装与测试【转】
http://blog.csdn.net/baihuaxiu123/article/details/51868142 一 摘要 如何大家之前做过web服务器的人都知道,nginx+lua与现在流行的n ...
- 【整理】C#文件操作大全
文件与文件夹操作主要用到以下几个类: 1.File类: 提供用于创建.复制.删除.移动和打开文件的静态方法,并协助创建 FileStream 对象. msdn:http://msdn.microsof ...
- 响应式Web设计- Viewport
什么是Viewport? viewport是用户网页的可视区域, 翻译为中文可以叫做"视区". 设置Viewport 一个常用的针对移动网页优化过的页面的Viewport meta ...
- javaEE(3)_servlet基础
一.Servlet简介 1.Servlet是sun公司提供的一门用于开发动态web资源的技术,Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序 ...