【学习笔记】CF1458D Flip and Reverse

其实是因为写不动带花树所以来水博客

这题妙啊。在学长的精心讲解下大概搞懂了。

首先这个操作就很神奇。考虑将 1 1 1看成 + 1 +1 +1 0 0 0看成 − 1 -1 1,求出其前缀和数组,然后每次就是两个前缀和相同的位置进行翻转,更神奇的是因为位置和值同时翻转了,所以你发现相当于是把前缀和数组的区间 [ l , r ] [l,r] [l,r]拿来翻转了。

于是就有一些更神奇的操作了。考虑构造无向图 G = ( V , E ) G=(V,E) G=(V,E),其中 V = { s u m i } V=\{sum_i\} V={sumi} E = { ( s u m i − 1 , s u m i ) ∣ 0 ≤ i < n } E=\{(sum_{i-1},sum_i)|0\le i<n\} E={(sumi1,sumi)∣0i<n},发现无论怎么操作这个序列对应的 G G G都是不变的,并且一个序列恰好经过所有边一次所以对应一个欧拉路径,那么大胆猜测一个欧拉路径和序列构成双射关系(?)。或者也可以换一个角度来看,相当于一个环可以顺时针或者逆时针走。并且这个图非常神奇, i i i只可能连到 i − 1 i-1 i1或者 i + 1 i+1 i+1,所以据此贪心的求出字典序最小的欧拉路径是容易的。

复杂度 O ( n ) O(n) O(n)

#include<bits/stdc++.h> #define inf 0x3f3f3f3f using namespace std; const int N=5e5+5; int T,n,Min,sum[N],edges[N][2]; string s; void dfs(int x){ if(edges[x][0])assert(x); if(!edges[x][0]&&!edges[x][1])return; if(edges[x][0]&&edges[x-1][1]>1||!edges[x][1]){ cout<<0;edges[x][0]--,edges[x-1][1]--,dfs(x-1); } else { cout<<1;edges[x][1]--,edges[x+1][0]--,dfs(x+1); } } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>T; while(T--){ cin>>s,n=s.size();Min=0;sum[0]=0; for(int i=1;i<=n;i++){ sum[i]=sum[i-1]+(s[i-1]=='1'?1:-1); Min=min(Min,sum[i]); }for(int i=0;i<=n;i++){ sum[i]-=Min; }for(int i=0;i<=n;i++)edges[i][0]=edges[i][1]=0; for(int i=0;i<n;i++){ if(s[i]=='1'){ edges[sum[i]][1]++; edges[sum[i+1]][0]++; } else{ edges[sum[i]][0]++; edges[sum[i+1]][1]++; } } dfs(sum[0]);cout<<"\n"; } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17529947.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(7)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示