D
给定一序列 $a$ ,每次操作可以使指定位置的数变成整个序列的异或和,求达到目标序列的最少次数
设初始时异或和为 $x$ ,转化为每次将 $a_i$ 变为 $x$ 并将 $a_i$ 拿在手上下一次替换
显然有解当且仅当 $a\cup \{x\} \in b$
再考虑替换的过程,最后一定要用 $b_i$ 替换掉 $a_i$ ,这启发连边 $b_i\rightarrow a_i$ ,再从 $x$ 开始遍历每一条边
如果图是一个包含 $x$ 的连通块,则一定有一条 $1$ 欧拉路径覆盖所有边
如果不连通,或 $x$ 是孤立点/不在连通块内,则答案就是 $边数+连通块数-(x不是孤立点)$
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
| const int N=1e5+100; int n,a[N],b[N],x; int cnt,edge_cnt,block_cnt; int vis[N]; map<int, int> mp; vector<int> G[N];
void dfs(int x){ vis[x]=1; for(int y:G[x]) if (!vis[y]) dfs(y); }
int main(){ scanf("%d",&n); for(rei i=1;i<=n;++i) scanf("%d",&a[i]),++mp[ a[i] ],x^=a[i]; for(rei i=1;i<=n;++i) scanf("%d",&b[i]),--mp[ b[i] ]; ++mp[x]; for(auto it:mp) if(it.second<0) return puts("-1"),0; for(auto &it:mp) it.second=++cnt; for(rei i=1;i<=n;++i) if(a[i]!=b[i]){ rei u=mp[ b[i] ],v=mp[ a[i] ]; G[u].push_back(v),G[v].push_back(u); ++edge_cnt; } for(rei i=1;i<=cnt;++i) if(G[i].size()) if(!vis[i]) ++block_cnt,dfs(i); printf("%d\n",edge_cnt+block_cnt-(!G[ mp[x] ].empty())); getchar(),getchar(); return 0; }
|
E
$2\leq N\leq 400$ 只火鸡, $m$ 个人,每人指定两只火鸡2 $x,y$ ,若两只都活着,则会等概率随机吃掉一只;若只活着一只,则悲吃掉;若都死亡则不做操作。第 $1$ 个人到第 $m$ 个人依次操作,求有多少 $(i,j)$ 满足最终时刻 $i,j$ 可能都活着
考虑如何使 $i$ 存活:第 $I$ 人选中 $i,j$ 只,则必须让 $j$ 死亡 ,则在第 $1\sim I-1$ 中第 $j$ 只不能死亡
而如果选择了 $(i,j),(i,k)$ 则如果前面的人选择 $(j,k)$ ,则第 $i$ 只必死
对于第 $i$ 只,设 $S_i$ 表示为了使 $i$ 存活需要保护的鸡的编号,从后往前扫到 $(x,y)$ :
- 初始时 $S_i=\{i\}$
- 不妨设 $x\in S_i , y\notin S_i$ ,则将 $y$ 加入 $S_i$
- 若 $x,y\in S_i$ ,则 $i$ 一定会死亡
再考虑鸡 $(i,j)$ 的存活:枚举 $i,j$ 并判断 $S_i\cap S_j$ 是否为空
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
| const int N=2e5+100; int n,m,ans,x[N],y[N],dead[N]; bitset<410> f[401];
int main(){ scanf("%d%d",&n,&m); for(rei i=1;i<=m;++i) scanf("%d%d",&x[i],&y[i]); for(rei i=1;i<=n;++i){ f[i][i]=1; for(rei j=m;j;--j){ rei u=f[i][ x[j] ],v=f[i][ y[j] ]; u&&v ? dead[i]=1 : 0; u ? f[i][ y[j] ]=1 : (v ? f[i][ x[j] ]=1 : 0); } } for(rei i=1;i<=n;++i){ if(dead[i]) continue; for(rei j=i+1;j<=n;++j){ if(dead[j]) continue; ans+=!((f[i]&f[j]).count()); } } printf("%d\n",ans); getchar(),getchar(); return 0; }
|