BZOJ 4197 NOI 2015 寿司晚宴
题面
Description
为了庆祝 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 的结果。
Samples
input:
3 10000
Sample Output
9
HINT
\(2≤n≤500\)
\(0<p≤1000000000\)
Solution
考虑\(n\)比较小的情况: 我们用f[i][j][k]表示到第\(i\)个数, 其中两个取的质因子情况分别为\(j\)和\(k\)的方案数, 01背包去掉第一维直接递推即可. 时间复杂度: \(O(n \times 2^{2n})\)
我们注意到, 对于一个数\(n\), 其大于\(\sqrt{n}\)的质因数最多只有一个, 因此我们对小于\(500\)的质数进行分组, \(\le \sqrt{500}\)的分为一组, \(> \sqrt{500}\)的分为另一组, 则每个数至多只会包含一个第二组的质因数. 我们首先对第一组的素数按照前面的方法进行状压DP, 再考虑第二组.
我们对第二组中每个素数记录一个集合\(S\), 表示包含有这一个质因子的数的集合. 对于同一个\(S\)中的数, 要么两个人都不选, 要么只由一个人选. 因此对于一个集合, 我们用g[i = 0 / 1][j][k]来表示由\(i\)来选这个集合中的数, 且两个人所选小于等于\(\sqrt{n}\)的约数情况分别为\(j\), \(k\)的方案数. 开始时\(g[0 / 1][j][k] = f[j][k]\). 对于同一个集合中的一个元素\(a\), 我们有如下转移:
\]
当处理完一个集合中的数后, 我们更新\(f\)数组:
\]
其中\(f[j][k]\)表示更新前的\(f\)值. 将其减去的原因是\(g[0]\)和\(g[1]\)都计算了一次整个集合都不取的情况, 因此要减掉一次.
注意到有一些数不存在大于\(\sqrt{500}\)的因数, 我们把它们和小于等于\(\sqrt{500}\)的放在一起计算即可.
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#define min std::min
#define vector std::vector
const int N = 500;
int n, p;
int prm[N], isNotPrime[N + 1], cnt;
vector<int> bck[N];
inline void getPrime()
{
memset(isNotPrime, 0, sizeof(isNotPrime));
cnt = 0;
for(int i = 2; i <= 500; ++ i)
{
if(! isNotPrime[i]) prm[cnt ++] = i;
for(int j = 0; j < cnt && i * prm[j] <= 500; ++ j)
{
isNotPrime[i * prm[j]] = 1;
if(i % prm[j] == 0) break;
}
}
}
int main()
{
scanf("%d%d", &n, &p);
getPrime();
int bnd = 8;
int f[1 << bnd][1 << bnd]; memset(f, 0, sizeof(f)); f[0][0] = 1;
for(int i = 2; i <= min(n, 22); ++ i)
{
int stt = 0; for(int j = 0; j < bnd; ++ j) if(i % prm[j] == 0) stt |= 1 << j;
for(int j = (1 << bnd) - 1; ~ j; -- j) for(int k = (1 << bnd) - 1; ~ k; -- k)
f[j | stt][k] = (f[j | stt][k] + f[j][k]) % p, f[j][k | stt] = (f[j][k | stt] + f[j][k]) % p;
}
for(int i = 23; i <= n; ++ i)
{
int flg = 0;
for(int j = cnt - 1; j >= 8; -- j) if(i % prm[j] == 0)
{
flg = 1;
bck[j].push_back(i);
}
if(! flg)
{
int stt = 0; for(int j = 0; j < bnd; ++ j) if(i % prm[j] == 0) stt |= 1 << j;
for(int j = (1 << bnd) - 1; ~ j; -- j) for(int k = (1 << bnd) - 1; ~ k; -- k)
f[j | stt][k] = (f[j | stt][k] + f[j][k]) % p, f[j][k | stt] = (f[j][k | stt] + f[j][k]) % p;
}
}
int g[2][1 << bnd][1 << bnd];
for(int i = 8; i < cnt; ++ i) if(! bck[i].empty())
{
for(int j = 0; j < 2; ++ j) for(int k = 0; k < 1 << bnd; ++ k) for(int l = 0; l < 1 << bnd; ++ l) g[j][k][l] = f[k][l];
for(auto cur : bck[i])
{
int stt = 0; for(int j = 0; j < bnd; ++ j) if(cur % prm[j] == 0) stt |= 1 << j;
for(int j = (1 << bnd) - 1; ~ j; -- j) for(int k = (1 << bnd) - 1; ~ k; -- k)
g[0][j | stt][k] = (g[0][j | stt][k] + g[0][j][k]) % p, g[1][j][k | stt] = (g[1][j][k | stt] + g[1][j][k]) % p;
}
for(int j = 0; j < 1 << bnd; ++ j) for(int k = 0; k < 1 << bnd; ++ k) f[j][k] = ((g[0][j][k] + g[1][j][k]) % p - f[j][k] + p) % p;
}
int ans = 0;
for(int i = 0; i < 1 << bnd; ++ i) for(int j = 0; j < 1 << bnd; ++ j) if((i & j) == 0) ans = (ans + f[i][j]) % p;
printf("%d\n", ans);
}
BZOJ 4197 NOI 2015 寿司晚宴的更多相关文章
- BZOJ 4197 NOI 2015 寿司晚宴 状压DP
4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 694 Solved: 440[Submit][Status] ...
- [NOI 2015]寿司晚宴
Description 题库链接 给定 \(2\sim n\) 一共 \(n-1\) 个数字,第一个人选择一些数字,第二个人选择一些数字,要求第一个人选的任意一个数字和第二个人选择的任意一个数字都互质 ...
- NOI 2015 寿司晚宴 (状压DP+分组背包)
题目大意:两个人从2~n中随意取几个数(不取也算作一种方案),被一个人取过的数不能被另一个人再取.两个人合法的取法是,其中一个人取的任何数必须与另一个人取的每一个数都互质,求所有合法的方案数 (数据范 ...
- [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机
[LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机 题意 给定平面上的 \(n\) 个整点 \((x_i,y_i)\), 一共有两个问题. 第一个问题是从原 ...
- [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会
[LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会 题意 给定一个长度为 \(n\) 的字符串 \(s\), 对于所有 \(r\in[1,n]\) 求出 \(s\ ...
- bzoj 4199 && NOI 2015 品酒大会
一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 ...
- [bzoj 4196][NOI 2015]软件包管理器
大概算是一道模板题吧? 就是细节有点多 罗列一下: 如果习惯从1开始搞树的编号的话,处理输入进来的那个依赖关系在加边的时候两个都要+1,体现在代码就是i要从2枚举到n,然后输入进来的那个数要+1 这道 ...
- bzoj 4198 [ Noi 2015 ] 荷马史诗 —— 哈夫曼编码(k叉哈夫曼树)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4198 第一次写哈夫曼树!看了很多博客. 哈夫曼树 & 哈夫曼编码:https://w ...
- BZOJ 4197: [Noi2015]寿司晚宴( dp )
N^0.5以内的质数只有8个, dp(i, j, k)表示用了前i个大质数(>N^0.5), 2人选的质数(<=N^0.5)集合分别为j, k时的方案数. 转移时考虑当前的大质数p是给哪个 ...
随机推荐
- TCP/IP网络编程之网络编程和套接字
网络编程和套接字 网络编程又称为套接字编程,就是编写一段程序,使得两台连网的计算机彼此之间可以交换数据.那么,这两台计算机用什么传输数据呢?首先,需要物理连接,将一台台独立的计算机通过物理线路连接在一 ...
- loj2291 「THUSC 2016」补退选
ref pkusc 快到了,做点 thusc 的题涨涨 rp-- #include <iostream> #include <cstring> #include <cst ...
- Spring MVC学习总结
Spring MVC学习总结 Spring MVC学习路(一) 下载配置文件 Spring MVC学习路(二) 设置配置文件 Spring MVC学习路(三) 编写第一个demo Spring MVC ...
- 2、HTML基础总结 part-2
1.表单一 <html> <body> <form> 姓名: <input type="text" name="name&quo ...
- 【清华集训】小Y和地铁
图已挂,前往luogu 题目: 小 $\rm Y$ 是一个爱好旅行的 $\rm OIer$.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁.她发现每条地铁线路可以看成平面上的一条 ...
- 浅谈我所见的CSS组织风格
1.简单组织(见习级) projectName ├─css | └style.css 优点:简单,单一文件,适合一些简单项目. 缺点:过度集中,没有模块化,无法适应大型项目. 2.公共组织(见习级) ...
- day02_02.能被3整除的个位数为6的数
第2题 能被3整除的个位数为6的数 难度增加一点点,再接再厉 注意: 把一些限制条件,用PHP编程的语言来执行 题目:输出100以内(不含100)能被3整除且个位数为6的所有整数 <?php f ...
- c#中dynamic ExpandoObject的用法
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- [python][django学习篇][5]选择数据库版本(默认SQLite3) 与操作数据库
推荐学习博客:http://zmrenwu.com/post/6/ 选择数据库版本(SQLite3) 如果想选择MySQL等版本数据库,请先安装MySQL并且安装python mysql驱动,这里不做 ...
- leetcode NO.349 两个数组的交集 (python实现)
来源 https://leetcode-cn.com/problems/intersection-of-two-arrays/ 题目描述 给定两个数组,写一个函数来计算它们的交集. 例子: 给定 nu ...