Codeforces 1221 G Graph And Numbers
这种比赛时只有11个人做出来的题一般来说都是暴难的, 我也不知道我怎么搞出来的www
看完这个题第一感觉就是要容斥,至少有一条某种边的方案已经比较难求了,而直接算三种边都至少存在一条的方案数就更难了2333
那么不妨考虑从反面容斥吧
设把三种边的存在情况表示成三进制的话,1表示至少有一条 ,0表示一条都没有,?表示这种边没有限制,那么容斥可以得到的是 : f[111] = f[???] - (f[0??]+f[?0?]+f[??0]) + (f[00?]+f[0?0]+f[?00]) - f[000]
证明可以通过二项式系数的关系导出,并且可以推广到N维形式。
显然等号右边的每个f[]都是比较好求的(但是会涉及很多算法),不过注意一些f[]是恒等的(根据图的对称性可得),所以不用每个f[]都去写一个函数算。算等号右边的f[]贡献了本题的大部分码量,这里就不一个一个说了,相信你们都能想出来的hhhhh
最后注意一下f[000],当且仅当 m==0 时 f[000]=2^n;否则 f[000]=0。
我一开始就因为这个WA了,想当然以为不可能每种边都没有(I'm reall a bro in bro),即 f[000]=0.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #include<bits/stdc++.h> #define ll long long using namespace std; const int N=1200005; int n,m,v[55],p[55],M,f[N]; bool g[55][55]; ll ans,all; inline bool Can( int S, int ad){ for ( int i=0;i<M;i++) for ( int j=i+1;j<M;j++) if (g[i+ad][j+ad]&&((1<<i)&S)&&((1<<j)&S)) return 0; return 1; } inline void Get1(){ for ( int s=0;s<(1<<M);s++) if (Can(s,0)) f[s]++; } inline void maintain(){ for ( int i=0;i<M;i++) for ( int j=0;j<(1<<M);j++) if (!((1<<i)&j)) f[j|(1<<i)]+=f[j]; } inline ll Get2(){ ll an=0; for ( int s=0,now,al=(1<<M)-1;s<(1<<(n-M));s++) if (Can(s,M)){ now=0; for ( int i=M;i<n;i++) if ((1<<(i-M))&s) for ( int j=0;j<M;j++) if (g[i][j]) now|=1<<j; an+=f[al^now]; } return an; } inline ll solve1(){ /* meet in the middle: 一半: 枚举合法二进制并用FMT的处理(类似高维每维值域{0,1}的前缀和) 映射到所有包含它的二进制上 另一半: 枚举合法二进制,直接找FMT数组对应的位置加就OK了 */ Get1(); maintain(); return Get2(); } int getfa( int x){ return p[x]==x?x:(p[x]=getfa(p[x]));} inline ll solve2(){ ll an=1; for ( int i=0;i<n;i++) p[i]=i; for ( int i=0,fa,fb;i<n;i++) for ( int j=i+1;j<n;j++) if (g[i][j]){ fa=getfa(i),fb=getfa(j); if (fa!=fb) p[fa]=fb; } for ( int i=0;i<n;i++) if (v[getfa(i)]!=2) v[p[i]]=2,an<<=1; return an; } inline ll solve3(){ ll an=1; for ( int i=0;i<n;i++) for ( int j=i+1;j<n;j++) if (g[i][j]) v[i]=v[j]=3; for ( int i=0;i<n;i++) if (v[i]!=3) an<<=1; return an; } bool color( int x, int c){ v[x]=c; for ( int i=0;i<n;i++) if (g[x][i]) if (v[i]==v[x]) return 0; else if (v[i]<4&&!color(i,9-c)) return 0; return 1; } inline ll solve4(){ ll an=1; for ( int i=0;i<n;i++) if (v[i]<4) if (!color(i,4)) return 0; else an<<=1; return an; } int main(){ scanf ( "%d%d" ,&n,&m),all=(1ll<<n)-1,M=n+1>>1; if (!m) ans-=all+1; //000 type for ( int U,V;m;m--) scanf ( "%d%d" ,&U,&V),U--,V--,g[V][U]=g[U][V]=1; ans+=all+1; // ??? type ans-=2*solve1(); // 0?? and ??0 type , cause its symmetry , we can simply double the ans ans-=solve2(); // ?0? type ans+=2*solve3(); // ?00 and 00? type , similar to solve1() ans+=solve4(); //0?0 type cout<<ans<<endl; return 0; } |
我爱学习,学习使我快乐
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· DeepSeek本地性能调优
· 一文掌握DeepSeek本地部署+Page Assist浏览器插件+C#接口调用+局域网访问!全攻略