题面

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\), 我们有如下转移:

\[\begin{cases} g[0][j \cup a][k] = g[0][j \cup a][k] + g[0][j][k] \\ g[1][j][k \cup a] = g[1][j][k \cup a] + g[1][j][k] \end{cases}
\]

当处理完一个集合中的数后, 我们更新\(f\)数组:

\[f[j][k] = g[0][j][k] + g[1][j][k] - f[j][k]
\]

其中\(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 寿司晚宴的更多相关文章

  1. BZOJ 4197 NOI 2015 寿司晚宴 状压DP

    4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 694  Solved: 440[Submit][Status] ...

  2. [NOI 2015]寿司晚宴

    Description 题库链接 给定 \(2\sim n\) 一共 \(n-1\) 个数字,第一个人选择一些数字,第二个人选择一些数字,要求第一个人选的任意一个数字和第二个人选择的任意一个数字都互质 ...

  3. NOI 2015 寿司晚宴 (状压DP+分组背包)

    题目大意:两个人从2~n中随意取几个数(不取也算作一种方案),被一个人取过的数不能被另一个人再取.两个人合法的取法是,其中一个人取的任何数必须与另一个人取的每一个数都互质,求所有合法的方案数 (数据范 ...

  4. [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机

    [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机 题意 给定平面上的 \(n\) 个整点 \((x_i,y_i)\), 一共有两个问题. 第一个问题是从原 ...

  5. [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会

    [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会 题意 给定一个长度为 \(n\) 的字符串 \(s\), 对于所有 \(r\in[1,n]\) 求出 \(s\ ...

  6. bzoj 4199 && NOI 2015 品酒大会

    一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 ...

  7. [bzoj 4196][NOI 2015]软件包管理器

    大概算是一道模板题吧? 就是细节有点多 罗列一下: 如果习惯从1开始搞树的编号的话,处理输入进来的那个依赖关系在加边的时候两个都要+1,体现在代码就是i要从2枚举到n,然后输入进来的那个数要+1 这道 ...

  8. bzoj 4198 [ Noi 2015 ] 荷马史诗 —— 哈夫曼编码(k叉哈夫曼树)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4198 第一次写哈夫曼树!看了很多博客. 哈夫曼树 & 哈夫曼编码:https://w ...

  9. BZOJ 4197: [Noi2015]寿司晚宴( dp )

    N^0.5以内的质数只有8个, dp(i, j, k)表示用了前i个大质数(>N^0.5), 2人选的质数(<=N^0.5)集合分别为j, k时的方案数. 转移时考虑当前的大质数p是给哪个 ...

随机推荐

  1. Nodejs-内置核心模块&npm包管理工具

    1.核心模块的意义 如果只是在服务器运行JavaScript代码,其实意义不大(浏览器就可以解决)因为无法实现功能(读写文件,访问网络) Node的用处在于本身还提供了一系列的功能模块,用于与操作系统 ...

  2. vrpie在Visio Studio 中无法调试的问题

    最近这这几天一直在研究vrpie,之前不能调试,一调试就出问题,打开那个生成的htm文件是没问题的,最初的解决方法是不通过调试来打可那个htm页面,但是这样比较麻烦,因为经常需要和服务器交互,就只能用 ...

  3. 【Best Time to Buy and Sell Stock II】cpp

    题目: Say you have an array for which the ith element is the price of a given stock on day i. Design a ...

  4. 【LoadRunner】场景执行报错“failed: WSA_IO_PENDING”

    问题:性能测试场景执行报“failed: WSA_IO_PENDING”错误 解决方法: 添加web_set_sockets_option("OVERLAPPED_SEND", & ...

  5. 【.NET MVC分页】.NET MVC 使用pagelist 分页

    1.安装 2. 在NuGet程序包管理控制台 ,输入Install-Package PagedList.mvc 安装PagedList 和PageList.Mvc; 3. @{ Layout = nu ...

  6. Event Loop详解

    1.进程,单线程与多线 进程: 运行的程序就是一个进程,比如你正在运行的浏览器,它会有一个进程. 线程: 程序中独立运行的代码段. 一个进程由单个或多个线程组成,线程是负责执行代码的. 2.单线程与多 ...

  7. Ubuntu下建立Pycharm快捷方式

    修改 Exec, Icon 路径,将文件保存 pycharm.desktop,拖到unity侧边栏 [Desktop Entry]Categories=Development;Comment[zh_C ...

  8. 【Luogu】P2485计算器(快速幂,exgcd和Bsgs模板)

    题目链接 题目描述非常直接,要求你用快速幂解决第一问,exgcd解决第二问,bsgs解决第三问. emmmm于是现学bsgs 第二问让求最小整数解好烦啊…… 假设我们要求得方程$ax+by=c(mod ...

  9. BZOJ3531 [Sdoi2014]旅行 【树剖 + 线段树】

    题目 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰.为了方便,我们用 ...

  10. So注入工具TsoInject开发文档

    So注入工具TsoInject开发文档 导语: 作为一个软件安全从业者而言,我们需要对某个App的关键函数就行Hook, 对于android而言,Smali层我们使用Xposed Hook框架,So层 ...