2025 省选模拟 6
2025 省选模拟 6
A.圣诞树
DP,计数题
考虑题目题目的两个限制
-
相邻两层彩球颜色集合不同
-
同层相邻两个彩球颜色不同
发现求出每一行恰好 \(j\) 个颜色后第二个限制很简单就解决了。
设 \(f_{i,j}\) 表示长度为 \(i\) 时恰好有 \(j\) 个颜色的方案数(对于一行考虑)
设 \(g_{i,j}\) 表示考虑前 \(i\) 行时第 \(i\) 恰有 \(j\) 个颜色的方案数(对于全局统计答案考虑)
设 \(s_i=\sum_jg_{i,j}\)
则 \(g\) 数组的转移为
对于 \(f\) 数组考虑一个从无到有的的过程去转移。
转移第一部分是增加一位,第二部分是增加一个数(第一次出现的位置),对于增加一个数我们考虑钦定从 \(1-j\) 依次去添加,最后有再乘上一个全排即可。
时间复杂度 \(O(l^2+\sum l+n+m)\).
B.过河
构造,二分图,dfs树
显然第一步得选取一个和 \(m\) 个三元关系都有关的猪,称其为关键点。
若样的关键点大于 \(2\) 显然有解,因为可以一边放一个,然后把其他的依次挪过去。
考虑关键点个数等于 \(1\) 时。
逆向思维去想,最后一步一定是移动关键点,所以一定有一个关键点再次过河的过程。
考虑这个过程,分为两步。
-
第一步,此时关键点过河,未过河的点形成一些二元关系,但这些二元关系可能有交,发现当二元关系不存在奇环时,可以将所有二元关系拆开,即移动一个属于二元限制的点过河,此时两边显然不会有冲突,可以将关键点重新运回来,依旧不会冲突,然后将所有除关键点外的点移动过河即,即是一组合法解。但是若未过河的点形成了奇环,此时肯定不能将所有二元关系拆开,因为拆开后河对岸必定发生冲突,考虑破坏奇环。
-
第二步,发现最多有两次机会去破坏未过河的二元关系组成的奇环,即在河两边都没有冲突时(人在河中央也不会有冲突),将两个属于奇环且相邻的点运过河,再运输第二次时,会发生冲突,但是由于人在所以不会有冲突,此时再将特殊点运过河。运过河后如果还有奇环,此时还会有冲突,但由于人在所以不会有冲突,此时能再破坏一次。总共两次。
此时得到一个暴力的做法,即枚举两个点,然后跑黑白染色判断二分图,单次时间复杂度 \(O(n^2(n+m))\),可以使用线段树分治优化,虽然我优化后和 GGrun 暴力一个分(
考虑正解,依旧考虑枚举一个点,然后判断是否存在另一个点。
这个点一定是所有奇环的交集,但是由于环与环之间的 "异或" 操作导致无法统计全部数量。
注意到一些性质,两个奇环相交不会得到奇环,而一个奇环和一个偶环相交会得到奇环。
证明
考虑通过 总大小 - 交集 去判断奇偶性,由于交集部分贡献会乘 \(2\) 所以根据总大小即可判断奇偶。
考虑奇环和偶环相交后那些点是合法的
对于图中的红点是非法的,因为去掉后依旧会存在奇环,黄点是合法的,因为去掉后就能将两个奇环破坏掉。
考虑通过 dfs树 去找环
由于 dfs树 不能找到与偶环相交后的奇环,所以得额外去判断上面情况。
考虑对每个点维护子树内通过 奇环/偶环 返祖边所能达到最小的 \(dep\),可以通过前缀和优化 ,然后通过每个儿子的信息去判断上述情况(因为得在同一颗子树内,否则就成上图中下部黄点了),此时不用关心偶环与偶环相交生成的偶环,因为此时统计信息是最小能达到的 \(dep\),不用 "异或" 产生的环的信息也能完成。
合法点还得是所有能找到奇环的交,和上面一样前缀和差分优化即可。
时间复杂度 \(O(Tn(n+m))\)。
code
#include<bits/stdc++.h> using namespace std; #define int ll #define ll long long #define ull unsigned long long #define pii pair<int,int> #define fi first #define se second #define ls o<<1 #define rs o<<1|1 bool __M1;int __st; const int maxn=3030; const int inf=1e9; int T,n,m,t[maxn],a[maxn],b[maxn],c[maxn]; int fa[maxn],dep[maxn],f[maxn],g[maxn],s[maxn],tot; bool vis[maxn],in[maxn],GG[maxn]; vector<int>e[maxn]; inline void put(bool op){cout<<(op?"yes":"no")<<"\n";} void dfs(int o,int Fa) { vis[o]=in[o]=1,dep[o]=dep[Fa]+1,fa[o]=Fa; for(auto v:e[o]) if(v!=Fa) { if(!vis[v]) { dfs(v,o); f[o]=min(f[o],f[v]),g[o]=min(g[o],g[v]); if(f[v]<dep[o] and g[v]<dep[o]) GG[o]=1; s[o]+=s[v]; } else if(in[v]) { if((dep[o]-dep[v]+1)&1) { f[o]=min(f[o],dep[v]); ++s[o],--s[fa[v]],++tot; } else g[o]=min(g[o],dep[v]); } } in[o]=0; } inline void add(int u,int v) { e[u].push_back(v); e[v].push_back(u); } inline void sol() { cin>>n>>m; for(int i=1;i<=n;++i)t[i]=0; for(int i=1;i<=m;++i) { cin>>a[i]>>b[i]>>c[i]; ++t[a[i]],++t[b[i]],++t[c[i]]; } int mx=0; for(int i=1;i<=n;++i)mx=max(mx,t[i]); if(mx!=m)return put(0); int id=0; for(int i=1;i<=n;++i)if(mx==t[i])id=i; for(int A=1;A<=n;++A) if(A!=id) { for(int i=1;i<=n;++i) e[i].clear(),GG[i]=vis[i]=s[i]=0,f[i]=g[i]=inf; tot=0; for(int i=1;i<=m;++i) if(a[i]!=A and b[i]!=A and c[i]!=A) { if(id==a[i]) add(b[i],c[i]); else if(id==b[i]) add(a[i],c[i]); else add(a[i],b[i]); } for(int i=1;i<=n;++i) if(i!=id and !vis[i]) dfs(i,0); for(int i=1;i<=n;++i) if(!GG[i] and tot==s[i]) return put(1); } put(0); } bool __M2; signed main() { freopen("river.in","r",stdin); freopen("river.out","w",stdout); ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>T; while(T--)sol(); cerr<<"\n"<<(&__M1-&__M2)/1024/1024<<"MB\n"<<clock()-__st<<"ms\n"; cout.flush(),fclose(stdin),fclose(stdout); return 0; }
C.点对游戏
概率期望,树上问题
不难发现每个最终局面的概率相等。
记 \(a,b,c\) 为每个人最终选点的个数。
考虑计算贡献,考虑枚举一组点对,然后判断其距离是否合法,其对 A 的贡献为 \(\dfrac{\dbinom{n-2}{a-2,b,c}}{\dbinom{n}{a,b,c}}=\dfrac{a(a-1)}{n(n-1)}\),发现只用计算有多少组点对合法即可。
使用点分治或者 dsu 即可在 \(O(nm\log n)\) 复杂度解决。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· 深度对比:PostgreSQL 和 SQL Server 在统计信息维护中的关键差异