2022省选Day2T1解题报告
2022省选Day2T1解题报告
题目描述
给定个数,有次询问,每次给定个质数,你可以选出一些数满足选出的数的乘积可以被给定的个质数整除,每次询问求有多少种选法
题解
当我们拿到一个询问选法的题时,大概率不是数学就是
显然我们很容易看出需要容斥一手,但是发现如果直接容斥统计有点难
考虑正难则反,我们可以处理有多少种取法不满足条件
那么答案肯定就是 (是不满足条件的选法数)
我们先考虑部分分怎么做
对于的情况,我们发现的质数只有10个
那么答案肯定就是减去某一个质数不选的方案数,再加上某两个质数不选的方案数,再减去某三个质数不选的方案数……
然后考虑推广,我们发现对于一个数最多只会有一个大于的质因数
所以我们可以把大于的数单独处理
而且对于两个大于的质数,是不可能同时不选也就是相对独立的
所以我们的容斥可以拿的质数必须有的方案数去减
这种做法可以当作套路去记一下,类似的题还有luogu2150 [NOI2015] 寿司晚宴
那么对于小于的质数总共最多个()
所以我们考虑状压
我们可以求出表示状态为,且当前枚举的的质数为的集合里的元素个数(状态记录有哪几个质数不选)
然后枚举的质数,把这些质数从集合中剔除,并将状态为的答案乘上(指能被当前枚举的质数整除的数的个数)
然后对于状态中的奇偶性判断加或减就行了
代码
#include <ctime>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#define int long long
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
using namespace std;
const int maxn=1e6+5,Mod=998244353;
int n,a[maxn],m,cnt[2000+5],id[maxn],mp[2000+5];
int f[(1<<13)+5][350],cnt1[(1<<13)+5],ans;
bool is_prime[maxn];
vector<int>prime,s[2000+5];
void chkmax(int &x,int y) {if (x<y) x=y;}
void chkmin(int &x,int y) {if (x>y) x=y;}
int read() {
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while(ch<='9' && ch>='0') {x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
int lowbit(int x) {return x&(-x);}
int ksm(int a,int b) {
int res=1;
while(b) {
if (b&1) (res*=a)%=Mod;
b>>=1;(a*=a)%=Mod;
}
return res;
}
void init() {
is_prime[1]=1;
for (int i=2;i<=2000;i++) {
if (!is_prime[i]) {
id[i]=prime.size();
prime.push_back(i);
}
for (size_t j=0;j<prime.size() && i*prime[j]<=2000;j++) {
is_prime[i*prime[j]]=1;
if (i%prime[j]==0) break;
}
}
for (int i=2;i<=2000;i++) {
for (int j=0;j<prime.size();j++) {
if (i%prime[j]) continue;
s[i].push_back(j);
if (j<13) mp[i]|=(1<<j);
}
}
}
int calc(int x) {
int res=0;
while(x) {
x-=lowbit(x);
res++;
}
return res;
}
signed main() {
file(luogu8292);
n=read();
for (int i=1;i<=n;i++) {
a[i]=read();
cnt[a[i]]++;
}
init();
for (int i=0;i<(1<<13);i++) {
for (int j=2;j<=2000;j++) {
if (i&mp[j]) continue;
f[i][s[j].back()]+=cnt[j];
cnt1[i]+=cnt[j];
}
}
int q=read();
while(q--) {
m=read();
int tmp=0;ans=0;
for (int i=1;i<=m;i++) {
a[i]=read();
if (id[a[i]]<13) tmp|=(1<<id[a[i]]);
}
// cout<<"tmp = "<<tmp<<endl;
sort(a+1,a+1+m);a[m+1]=-1;
for (int i=0;i<(1<<13);i++) {
if ((tmp|i)>tmp) continue;
int res=1,tot=cnt1[i];
for (int j=1;j<=m;j++) {
if (a[j]==a[j+1]) continue;
if (id[a[j]]<13) continue;
(res*=(ksm(2,f[i][id[a[j]]])-1+Mod)%Mod)%=Mod;
tot-=f[i][id[a[j]]];
}
(res*=ksm(2,tot))%=Mod;
if (calc(i)&1) ans=((ans-res)%Mod+Mod)%Mod;
else ans=(ans+res)%Mod;
// cout<<i<<' '<<tot<<endl;
}
cout<<ans<<endl;
}
return 0;
}
/*
---
/Y A\
\___/ /
\ /
\ /*
—————\ *
\*____
|* \
|*
\*
*
*
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现