题面

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. git pull免密码拉取

    ssh到服务器上,原来基于public/private key pair的方法不好使了. 1.1 创建文件存储GIT用户名和密码 在%HOME%目录中,一般为C:\users\Administrato ...

  2. 极简配置phpstorm+xdebug进行断点调试

    以前调试的时候各种var_dump()就能得到结果,现在入手别人开发的工作,由于不了解业务和代码逻辑,又要去修改bug,就造成了修改bug效率低,所以又拾起来了xdbug,顺便总结了一下phpstor ...

  3. hibernate 出错 集合

    Lazy="false"反而出错 错误信息: “System.Configuration.ConfigurationErrorsException”类型的异常在 Spring.Co ...

  4. 并发编程——多进程——multiprocessing开启进程的方式及其属性(3)

    开启进程的两种方式——Process 方式一:函数方法 from multiprocessing import Process import time def task(name): print('% ...

  5. 博客内插入bilibili视频

    原理 使用iframe标签,更改其中src的aid和cid,使其对应要插入的视频,即可在文章内插入bilibili视频 获取cid aid即为视频的av号,cid有两种获取方式,一是通过bilibil ...

  6. git和github基础入门

    一.git: 1.安装配置git: 1.1从官网或者该网址处下载:https://pan.baidu.com/s/1kU5OCOB#list/path=%2Fpub%2Fgit 1.2安装,一路nex ...

  7. 数据结构算法——链表的各种操作,C++和Python

    时隔已久,一直没更新博客,感觉很愧疚呀. 先贴上所有的代码.这个是用C++写的 #include "stdafx.h" //Author:Albert //Date: 2018.1 ...

  8. BZOJ3612 [Heoi2014]平衡 整数划分

    [Heoi2014]平衡 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 348  Solved: 273[Submit][Status][Discus ...

  9. Tortoise SVN 提示 clean up 然而 clean up 没卵用的解决方法

    当 svn 提示clean up时,而clean up 仍然没用的情况下 先下载 sqlite3.exe 然后 在svn目录下,.svn 隐藏文件夹中 有个 wc.db 的文件, 执行下面命令行  s ...

  10. [AGC003F] Fraction of Fractal(矩阵乘法)

    Description Snuke从他的母亲那里得到了生日礼物--一个网格.网格有H行W列.每个单元格都是黑色或白色.所有黑色单元格都是四联通的,也就是说,只做水平或垂直移动且只经过黑色单元格即可从任 ...