【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. 对于寿司晚宴这题,标准解 ...
随机推荐
- SQLServer同一实例下事务操作
参考代码: 引用Dapper public bool OrderAdd2(User user, Order order) { string dbString = ConfigurationManage ...
- 在linux下面安装mysql 确认 配置文件路径 my.cnf
1.确认服务器my.cnf 文件路径.但不知道那个是 2.通过which mysql命令来查看mysql的安装位置: 3.通过/usr/local/mysql/bin/mysqld --verbose ...
- C++遍历文件及文件夹代码
可以遍历目录包含的文件及文件夹 #include <string> #include <vector> #include <io.h> using std::vec ...
- codeforces Gym 100338F Spam Filter 垃圾邮件过滤器(模拟,实现)
阅读题, 概要:给出垃圾邮件和非垃圾邮件的集合,然后按照题目给出的贝叶斯公式计算概率一封邮件是垃圾邮件的概率. 逐个单词判断,将公式化简一下就是在垃圾邮件中出现的次数和在总次数的比值,大于二分之一就算 ...
- ObjectiveC中的赋值,对象拷贝,浅拷贝与深拷贝
在开发过程中我们经常会遇到对象拷贝的问题,下面我们分别讨论赋值操作.对象拷贝.以及浅拷贝(Shallow copy)与深拷贝(Deep copy)的区别与各自的实现方式. 一.不同对象的赋值操作 Ob ...
- SpringAOP 设计原理
1. 设计原理 引入了,代理模式. java 程序执行流: 如果从虚拟机的角度看,整个程序的过程就是方法的调用,我们按照方法的执行顺序,将方法调用成一串. 在方法之间有着Join Point 连接点 ...
- PWN题搭建
0x00.准备题目 例如:level.c #include <stdio.h> #include <unistd.h> int main(){ char buffer[0x10 ...
- x220 OS X 10.10.4安装
变色龙安装过程: 1.使用磁盘助手将按照盘写入独立的磁盘分区(AF格式,就是Apple的HPS格式): 2.安装启动时,用-v -f -x参数,分别为显示信息.重新build系统驱动.安全模式: 3. ...
- js 一维数组转成tree 对象
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- JS函数节流和防抖
看JS高级程序设计时,了解到一个概念--函数节流,是为了防止在高频率触发某些事件导致浏览器崩溃.最近又了解到另一个概念,防抖,感觉和函数节流很像,也查看了很多篇博文,算是理解了. 区别: 函数节流:频 ...