YACS 2022年02月月赛 甲组 开关灯

https://iai.sh.cn/problem/589

晚自修摸鱼 15 min 想了出来。

考虑朴素覆盖,显然不行。

换种思路,考虑一个数被多少数覆盖到了,发现 m 很小,直接状压。

f[S] 表示仅以 S 状态的覆盖到的数的数量,即 f[S] 贡献的数不能贡献到 f[T],TS

发现可以容斥,即枚举超集,然后减去即可。

再发现转移顺序可能很奇怪,那么记搜。

注意 int128

#include <bits/stdc++.h> #define int __int128 #define il inline using namespace std; il int rd() { int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } void pr(int x) { if(x<0) {putchar('-');x=-x;} if(x>9) pr(x/10); putchar(x%10+'0'); } const int N=(1<<16)+1; int n,m,mS,f[N],a[20]; il int gcd(int x,int y) { return !y?x:gcd(y,x%y); } il int lcm(int x,int y) { return x/gcd(x,y)*y; } il int cal(int S) { if(!S) return 0; int qwq=1; // cout<<S<<endl; for(int i=1;i<=m;i++) { if((S>>(i-1))&1) { qwq=lcm(qwq,a[i]); // cout<<": "<<i<<" "; } } // cout<<qwq<<" lcm\n"; return n/qwq; } il int dfs(int S) { if(f[S]!=-1) return f[S]; int SS=mS-S,qwq=cal(S); for(int T=SS;T;T=(T-1)&SS) { int U=(T|S); qwq-=dfs(U); } return f[S]=qwq; } il int cal1(int x) { int cnt=0; while(x) ++cnt,x-=(x&(-x)); return cnt; } signed main() { memset(f,-1,sizeof(f)); n=rd(); m=rd(); mS=(1<<m)-1; for(int i=1;i<=m;i++) a[i]=rd(); f[mS]=cal(mS); int ans=0; for(int i=1;i<=mS;i++) if(f[i]==-1) dfs(i); for(int i=1;i<=mS;i++) { if(cal1(i)%2!=0) ans+=f[i]; } pr(ans); return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/16049281.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示