题面传送门

题意:

  • 你有一个集合 \(S={2,3,\dots,n}\)
  • 你要选择两个集合 \(A\) 和 \(B\),满足:
  1. \(A \subseteq S\),\(B \subseteq S\),且 \(A \cap B=\varnothing\)
  2. 不存在两个数 \(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\) 的选择方法:

  1. \(p\) 在 \(A\) 中,那么选择的方案数为 \(2^{cnt_{\frac{n}{p},s}+1}\)(你可以看成从 \([1,\frac{n}{p}]\) 选择若干个质因子集合为 \(s\) 的集合然后将每个数乘以 \(p\))
  2. \(p\) 在 \(B\) 中,那么选择的方案数为 \(2^{cnt_{\frac{n}{p},t}+1}\)
  3. \(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+数论+容斥)的更多相关文章

  1. [NOI2015]寿司晚宴 --- 状压DP

    [NOI2015]寿司晚宴 题目描述 为了庆祝NOI的成功开幕,主办方为大家准备了一场寿司晚宴. 小G和小W作为参加NOI的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了n−1种不同的寿 ...

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

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

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

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

  4. 洛谷$P2150\ [NOI2015]$寿司晚宴 $dp$

    正解:$dp$ 解题报告: 传送门$QwQ$. 遇事不决写$dp$($bushi$.讲道理这题一看就感觉除了$dp$也没啥很好的算法能做了,于是考虑$dp$呗 先看部分分?$30pts$发现质因数个数 ...

  5. BZOJ 4197: [Noi2015]寿司晚宴 状压dp+质因数分解

    挺神的一道题 ~ 由于两个人选的数字不能有互质的情况,所以说对于一个质因子来说,如果 1 选了,则 2 不能选任何整除该质因子的数. 然后,我们发现对于 1 ~ 500 的数字来说,只可能有一个大于 ...

  6. [NOI2015]寿司晚宴——状压dp

    题目转化:将2~n的数分成两组,可以不选,使得这两组没有公共的质因子.求方案数. 选择了一个数,相当于选择了它的所有质因子. 30分: 发现,n<=30的时候,涉及到的质因子也就10个.2,3, ...

  7. B4197 [Noi2015]寿司晚宴 状压dp

    这个题一开始想到了唯一分解定理,然后状压.但是显然数组开不下,后来想到每个数(n<500)大于19的素因子只可能有一个,所以直接单独存就行了. 然后正常状压dp就很好搞了. 题干: Descri ...

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

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

  9. 【题解】洛谷P3959 [NOIP2017TG] 宝藏(状压DP+DFS)

    洛谷P3959:https://www.luogu.org/problemnew/show/P3959 前言 NOIP2017时还很弱(现在也很弱 看出来是DP 但是并不会状压DP 现在看来思路并不复 ...

随机推荐

  1. 无网环境安装docker之--rpm

    总体思路:找一台可以联网的linux,下载docker的RPM依赖包而不进行安装(yum localinstall),将所有依赖的rpm环境打包好,再在无网环境中解压逐一安装(rpm:  --forc ...

  2. 耗时一个月,整理出这份Hadoop吐血宝典

    本文目录: 一.HDFS 二.MapReduce 三.Yarn 四.Hadoop3.x 新特性 五.Hadoop 大厂面试真题解析 Hadoop 涉及的知识点如下图所示,本文将逐一讲解: 本文档参考了 ...

  3. RabbitMQ设计原理解析

    背景 RabbitMQ现在用的也比较多,但是没有过去那么多啦.现在很多的流行或者常用技术或者思路都是从过去的思路中演变而来的.了解一些过去的技术,对有些人来说可能会产生众里寻他千百度的顿悟,加深对技术 ...

  4. [no_code][Beta]设计和计划

    2020春季计算机学院软件工程(罗杰 任健) 2020春季计算机学院软件工程(罗杰 任健) 作业要求 Beta设计和计划 我们在这个课程的目标是 远程协同工作,采用最新技术开发软件 这个作业在哪个具体 ...

  5. spring cloud feign的各种配置的使用

    在上一节我们完成了feign的基本使用,学会了feign如何去调用其他微服务,这次我们来完成feign的一些自定义配置. 实现功能:     1.全局修改feign的配置和单独修改feign客户端的配 ...

  6. MySQL实战优化之InnoDB整体架构

    一.InnoDB 更新数据得整体架构 每个组件的作用说明: 用一条更新数据来说明每个主键得作用: update student set name = 'zhangsan' where id = 10 ...

  7. Linux下文件的三种时间标记:访问时间、修改时间、状态改动时间 (转载)

    在windows下,一个文件有:创建时间.修改时间.访问时间. 而在Linux下,一个文件也有三种时间,分别是:访问时间.修改时间.状态改动时间. 两者有此不同,在Linux下没有创建时间的概念,也就 ...

  8. 数值的整数次方 牛客网 剑指Offer

    数值的整数次方 牛客网 剑指Offer 题目描述 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方 class Solution: #run ...

  9. Python AttributeError: module 'string' has no attribute 'atoi'

    python2 中可以用string.atoi 在python3中会报错 替换的方案是 string.atoi(your_str) 替换为 int(your_str) 这个代码python2和pyth ...

  10. Android WebView 实现文件选择、拍照、录制视频、录音

    原文地址:Android WebView 实现文件选择.拍照.录制视频.录音 | Stars-One的杂货小窝 Android中的WebView如果不进行相应的设置,H5页面的上传按钮是无法触发And ...