UOJ #129 / BZOJ 4197 / 洛谷 P2150 - [NOI2015]寿司晚宴 (状压dp+数论+容斥)
题意:
- 你有一个集合 \(S={2,3,\dots,n}\)
- 你要选择两个集合 \(A\) 和 \(B\),满足:
- \(A \subseteq S\),\(B \subseteq S\),且 \(A \cap B=\varnothing\)
- 不存在两个数 \(x \in A\),\(y \in B\),且 \(\operatorname{gcd}(x,y)>1\)。
- 求满足条件的集合 \(A,B\) 的数量。
\(n \in [2,500]\)
通过分析题面可以发现,如果两个集合 \(A,B\) 满足条件,那么它们的质因子组成的集合一定不会重复。
先考虑 \(30\) 分的做法。\(30\) 以内的质数只有 \(10\) 个(\(2,3,5,7,11,13,17,19,23,29\))。
我们分别给这 \(10\) 个质数标号 \(1\) 到 \(10\)。这样我们可以使用一个 \(10\) 位二进制数表示质因子的选择情况。
例如 \((1011001100)_2\) 就表示集合中包含质因子 \(2,5,7,17,19\)。
再将 \(2\) 到 \(n\) 每个数分解质因数。记 \(fac_i\) 为 \(i\) 质因子的集合。
到这里,不少题解都使用了三维状压 \(dp\)。这里我要介绍一个不太一样的方法。
我们开一个数组 \(cnt_{i,j}\),其中 \(i \in [2,n],j \in [0,2^{10}-1]\)。
表示满足 \(2 \leq x \leq i\),\(fac_i \subseteq j\) 的 \(x\) 的个数
再设 \(dp_s\) 表示质因子集合为 \(s\) 的集合数量。
显然所有 \(fac_i \subseteq s\) 的 \(i\) 都可以被选,那么总共有 \(cnt_{n,i}\) 个数,每个数都有选与不选两种可能,故 \(dp_s=2^{cnt_{n,i}}\)
最后是统计答案,枚举质因子集合 \(s,t\)(根据条件 2,\(s\&t=0\)),两个集合的选择方法是独立的,因此,根据乘法原理,这一部分对答案的贡献为 \(dp_s \times dp_t\)。
但是这样做还不行。假设有一个集合 \(T={2,4}\),那么 \(T\) 在 \(dp_1\) 中被计算了一次,在 \(dp_3\) 中又被计算了一次,会被重复计算。
这时不难想到容斥原理。你对 \(dp\) 数组进行一遍容斥原理就可以了。
再考虑正解。\(n\) 从 \(30\) 扩大到了 \(500\),就不能像 \(30\) 分做法那样将一个质因子集合用二进制表示出来了。
但是注意到 \(\sqrt{500}\) 只有 \(22\),而 \(22\) 以内的质数只有 \(8\) 个。
那么我们可以用根号分治的思想将质数分成两类,一类是 \(\leq 22\) 的质数(我们称其为“小质数”),另一类是 \(\gt 22\) 的质数(我们称其为“大质数”)。
不难发现,\(1\) 到 \(500\) 中的数最多只有一个大质数因子。任意两个大质数乘起来都会 \(\gt 500\)。
换句话说,大质数的选择方案是独立的(是否选择 \(31\) 这个质因子不会影响 \(37\) 的选择方案)
我们枚举小质数因子的集合 \(s,t\),然后考虑每个大质数 \(p\) 的选择方法:
- \(p\) 在 \(A\) 中,那么选择的方案数为 \(2^{cnt_{\frac{n}{p},s}+1}\)(你可以看成从 \([1,\frac{n}{p}]\) 选择若干个质因子集合为 \(s\) 的集合然后将每个数乘以 \(p\))
- \(p\) 在 \(B\) 中,那么选择的方案数为 \(2^{cnt_{\frac{n}{p},t}+1}\)
- \(p\) 既不在 \(A\) 也不在 \(B\) 中,方案数为 \(1\)。
将三者加起来就是选择 \(p\) 的方案数。
将选择每个大质数的方案数乘起来就是选择大质数的方案数。
选择小质数的方案数和 \(30\) 分做法一样用乘法原理将两部分乘起来。
用容斥原理算一下就可以了。
/*
Contest: -
Problem: P2150
Author: tzc_wk
Time: 2020.7.31
*/
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define fillsmall(a) memset(a,0xcf,sizeof(a))
#define y1 y1010101010101
#define y0 y0101010101010
#define int long long
typedef pair<int,int> pii;
inline int read(){
int x=0,neg=1;char c=getchar();
while(!isdigit(c)){
if(c=='-') neg=-1;
c=getchar();
}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x*neg;
}
int n=read(),m=read();
inline int qpow(int x,int e){
int ans=1;
while(e){
if(e&1) ans=ans*x%m;
x=x*x%m;
e>>=1;
}
return ans;
}
int pr[505],num[505],pcnt=0;
bool vis[505];
inline void sieve(){
for(int i=2;i<=500;i++){
if(!vis[i]){
pr[++pcnt]=i;num[i]=pcnt;
for(int j=i+i;j<=500;j+=i) vis[j]=1;
}
}
}
int sumfac[505][1<<8];
int g[505][1<<8],gg[505][1<<8];
inline int calc_fac(int x){
int tmp=x,flg=0;
for(int i=2;i*i<=x;i++){
if(tmp%i==0){
flg|=(1<<(num[i]-1));
while(tmp%i==0) tmp/=i;
}
}
if(tmp>1){
if(num[tmp]>8) return 256;
else flg|=(1<<(num[tmp]-1));
}
return flg;
}
signed main(){
sieve();
fz(i,2,n){
int f=calc_fac(i);
for(int j=0;j<(1<<8);j++){
if((j&f)!=f) sumfac[i][j]=sumfac[i-1][j];
else sumfac[i][j]=sumfac[i-1][j]+1;
// cout<<i<<" "<<j<<" "<<sumfac[i][j]<<endl;
}
}
for(int i=0;i<(1<<8);i++) for(int j=0;j<(1<<8);j++){
if((i&j)==0){
// if(dp[i][n]==0||dp[j][n]==0) continue;
// cout<<i<<" "<<j<<" "<<dp[i][n]<<" "<<dp[j][n]<<endl;
int ans=1;
ans=ans*qpow(2,sumfac[n][i])%m;
ans=ans*qpow(2,sumfac[n][j])%m;
for(int k=23;k<=n;k++){
if(num[k]){
// if(k==23) cout<<i<<" "<<j<<" "<<qpow(2,sumfac[n/k][i]+1)+qpow(2,sumfac[n/k][j]+1)-1<<endl;
ans=ans*(qpow(2,sumfac[n/k][i]+1)+qpow(2,sumfac[n/k][j]+1)-1+m)%m;
}
}
g[i][j]=ans;
// cout<<i<<" "<<j<<" "<<g[i][j]<<endl;
}
}
for(int i=0;i<(1<<8);i++) for(int j=0;j<(1<<8);j++){
if((i&j)==0){
for(int k=0;k<(1<<8);k++){
if((j&k)!=k) continue;
gg[i][j]=(gg[i][j]+(int)pow(-1,__builtin_popcount(j^k))*g[i][k]+m)%m;
}
// cout<<i<<" "<<j<<" "<<gg[i][j]<<endl;
}
}
int sum=0;
for(int i=0;i<(1<<8);i++) for(int j=0;j<(1<<8);j++){
if((i&j)==0){
int x=0;
for(int k=0;k<(1<<8);k++){
if((i&k)!=k) continue;
x=(x+(int)pow(-1,__builtin_popcount(i^k))*gg[k][j]+m)%m;
}
sum=(sum+x)%m;
// cout<<i<<" "<<j<<" "<<x<<endl;
}
}
cout<<sum<<endl;
return 0;
}
UOJ #129 / BZOJ 4197 / 洛谷 P2150 - [NOI2015]寿司晚宴 (状压dp+数论+容斥)的更多相关文章
- [NOI2015]寿司晚宴 --- 状压DP
[NOI2015]寿司晚宴 题目描述 为了庆祝NOI的成功开幕,主办方为大家准备了一场寿司晚宴. 小G和小W作为参加NOI的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了n−1种不同的寿 ...
- 【BZOJ4197】[Noi2015]寿司晚宴 状压DP+分解质因数
[BZOJ4197][Noi2015]寿司晚宴 Description 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴 ...
- bzoj4197 [Noi2015]寿司晚宴——状压DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4197 首先,两个人选的数都互质可以看作是一个人选了一个数,就相当于选了一个质因数集合,另一个 ...
- 洛谷$P2150\ [NOI2015]$寿司晚宴 $dp$
正解:$dp$ 解题报告: 传送门$QwQ$. 遇事不决写$dp$($bushi$.讲道理这题一看就感觉除了$dp$也没啥很好的算法能做了,于是考虑$dp$呗 先看部分分?$30pts$发现质因数个数 ...
- BZOJ 4197: [Noi2015]寿司晚宴 状压dp+质因数分解
挺神的一道题 ~ 由于两个人选的数字不能有互质的情况,所以说对于一个质因子来说,如果 1 选了,则 2 不能选任何整除该质因子的数. 然后,我们发现对于 1 ~ 500 的数字来说,只可能有一个大于 ...
- [NOI2015]寿司晚宴——状压dp
题目转化:将2~n的数分成两组,可以不选,使得这两组没有公共的质因子.求方案数. 选择了一个数,相当于选择了它的所有质因子. 30分: 发现,n<=30的时候,涉及到的质因子也就10个.2,3, ...
- B4197 [Noi2015]寿司晚宴 状压dp
这个题一开始想到了唯一分解定理,然后状压.但是显然数组开不下,后来想到每个数(n<500)大于19的素因子只可能有一个,所以直接单独存就行了. 然后正常状压dp就很好搞了. 题干: Descri ...
- BZOJ 4197 NOI 2015 寿司晚宴 状压DP
4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 694 Solved: 440[Submit][Status] ...
- 【题解】洛谷P3959 [NOIP2017TG] 宝藏(状压DP+DFS)
洛谷P3959:https://www.luogu.org/problemnew/show/P3959 前言 NOIP2017时还很弱(现在也很弱 看出来是DP 但是并不会状压DP 现在看来思路并不复 ...
随机推荐
- Java并行任务框架Fork/Join
Fork/Join是什么? Fork意思是分叉,Join为合并.Fork/Join是一个将任务分割并行运行,然后将最终结果合并成为大任务的结果的框架,父任务可以分割成若干个子任务,子任务可以继续分割, ...
- Java集合 - 集合知识点总结概述
集合概述 概念:对象的容器,定义了对多个对象进项操作的的常用方法.可实现数组的功能. 和数组的区别: 数组长度固定,集合长度不固定. 数组可以存储基本类型和引用类型,集合只能存储引用类型. 位置: j ...
- Java:动态代理小记
Java:动态代理小记 对 Java 中的 动态代理,做一个微不足道的小小小小记 概述 动态代理:当想要给实现了某个接口的类中的方法,加一些额外的处理.比如说加日志,加事务等.可以给这个类创建一个代理 ...
- 微信小程序的发布流程
一.背景 在中大型的公司里,人员的分工非常仔细,一般会有不同岗位角色的员工同时参与同一个小程序项目.为此,小程序平台设计了不同的权限管理使得项目管理者可以更加高效管理整个团队的协同工作 以往我们在开发 ...
- 第6次 Beta Scrum Meeting
本次会议为Beta阶段第6次Scrum Meeting会议 会议概要 会议时间:2021年6月8日 会议地点:「腾讯会议」线上进行 会议时长:15min 会议内容简介:对完成工作进行阶段性汇报:对下一 ...
- Unity 制作不规则形状button
在游戏开发中,我们有时需要制作不规则形状的按键. Unity3d中使用UGUI的Button控件只能实现规则的长方形按钮.而通过给Button的Image组件添加对应的贴图(sprite)我们可以实现 ...
- RabbitMQ处理未被路由的消息
我们经常使用消息队列进行系统之间的解耦,日志记录等等.但是有时候我们在使用 RabbitMQ时,由于exchange.bindKey.routingKey没有设置正确,导致我们发送给交换器(excha ...
- 2021.10.9考试总结[NOIP模拟72]
T1出了个大阴间题 状压\(DP\),记当前状态的代价和与方案数.状态\(\Theta(2^nn)\),转移\(\Theta(n)\). 发现每个状态的最大值只会是所选集合的\(max\)或加一.于是 ...
- python +spatialite + window 解决方案(https://www.jianshu.com/p/5bc7d8b7b429)
运行环境在windows 10 64bit.先将python安装完成.然后,到 spatilite官网 找到MS(即Microsoft)版本,下载64位的mod_spatialite,将其先解压到目标 ...
- mybatis竟然报"Invalid value for getInt()"
目录 背景 场景 初探 再探 结局 背景 使用mybatis遇到一个非常奇葩的问题,错误如下: Cause: org.apache.ibatis.executor.result.ResultMapEx ...