题目描述

为了庆祝 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 取模)。注意一个人可以不吃任何寿司。

输入

输入文件的第 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的更多相关文章

  1. [UOJ#129][BZOJ4197][Noi2015]寿司晚宴

    [UOJ#129][BZOJ4197][Noi2015]寿司晚宴 试题描述 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司 ...

  2. [BZOJ4197][Noi2015]寿司晚宴

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

  3. bzoj4197 [Noi2015]寿司晚宴——状压DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4197 首先,两个人选的数都互质可以看作是一个人选了一个数,就相当于选了一个质因数集合,另一个 ...

  4. BZOJ4197 [Noi2015]寿司晚宴 【状压dp】

    题目链接 BZOJ4197 题解 两个人选的数都互质,意味着两个人选择了没有交集的质因子集合 容易想到将两个人所选的质因子集合作为状态\(dp\) \(n\)以内质数很多,但容易发现\(\sqrt{n ...

  5. UOJ129 NOI2015 寿司晚宴 数论、状压DP

    传送门 数论题\(n \leq 500\)肯定是什么暴力算法-- 注意到每一个数\(> \sqrt{n}\)的因子最多只有一个,这意味着\(> \sqrt{n}\)的因子之间是独立的,而只 ...

  6. 【BZOJ4197】[Noi2015]寿司晚宴 状压DP+分解质因数

    [BZOJ4197][Noi2015]寿司晚宴 Description 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴 ...

  7. BZOJ_4197_[Noi2015]寿司晚宴_状态压缩动态规划

    BZOJ_4197_[Noi2015]寿司晚宴_状态压缩动态规划 Description 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被 ...

  8. BZOJ 4197: [Noi2015]寿司晚宴 状态压缩 + 01背包

    4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec  Memory Limit: 512 MB Description 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿 ...

  9. NOI2015 寿司晚宴

    今年NOI确实是在下输了.最近想把当时不会做的题都写一下. 题意 从2到n(500)这些数字中,选若干分给A,若干分给B,满足不存在:A的某个数和B的某个数的GCD不等于1. 对于寿司晚宴这题,标准解 ...

随机推荐

  1. Scanner-String-StringBuilder-API

    1.能够明确API的使用步骤     1)打开帮助文档     2)点击显示,找到索引,看到输入框     3)你要找谁?在输入框里输入,然后回车     4)看包:java.lang下的类不需 ...

  2. 【读书笔记】构建之法(CH4~CH6)

    从chapter4至chapter6,围绕着构建过程的合作讨论构建之法,而合作与个人工作的区别却以一个微妙的问题为开端:阅读别人的代码有多难? 两人合作:(驾驶员与领航员) 合作要注意代码风格规范与设 ...

  3. CPU性能的评价

    人们通常用benchmark 来衡量CPU的性能,常见的benchmark有dhrystone和coremark. 由于dhrystone 受编译器影响比较大,所以,结果不是很准确,现在大多采用cor ...

  4. IOS typedef 函数指针的用法

    代码简化, 促进跨平台开发的目的. typedef 行为有点像 #define 宏,用其实际类型替代同义字. 不同点:typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换. 用 ...

  5. KTU Programming Camp (Winter Training Day 1)

    A.B.C(By musashiheart) 0216个人赛前三道题解 E(By ggg) Gym - 100735E Restore H(by pipixia) Gym - 100735H

  6. 1991: C语言实验——大小写转换

    1991: C语言实验——大小写转换 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 183  Solved: 109[Submit][Status][We ...

  7. shell脚本,如何破解字符串对应的md5sum前的RANDOM对应数字?

    已知下面的字符串是通过RANDOM随机数变量md5sum|cut-c 1-8截取后的结果,请破解这些字符串对应的md5sum前的RANDOM对应数字?[root@localhost md5]# cat ...

  8. javase(8)_集合框架_List、Set、Map

    一.集合体系(不包括Queue体系) 二.ArrayList ArrayList的属性 private transient Object[] elementData; //存储元素 private i ...

  9. 基于Vue+VueRouter+ModJS+Fis3快速搭建H5项目总结

    技术选型 • 框架 - Vue+VueRouter • 相比较于react/angular/avalon ? • 简单轻量,社区配套完整• 模块化 - ModJS • 相比较于require/seaj ...

  10. Comet OJ 热身赛-principal

    这题的话,我们分析一下,入栈的操作是: 栈空 栈顶元素和当前操作元素不属于同一类括号 栈顶元素和当前操作元素属于同一类括号,但是并不是左括号在前,右括号在后 上面三个条件有任意一个满足都应该入栈,如果 ...