1 条题解
-
0
考虑把 的序列转成极长连续段长度的序列 。由于每次能消掉长度为 或 的相等连续子序列。所以我们可以删除任意一个长度 的极长段。
那么,我们把 序列看成 序列,分别表示 和 。那么一次操作相当于删掉一个 并且把其左右合并到一起。具体地,从 变为 。能看作为把 左右两端消除掉。
我们成功把问题转到了这个序列上,首先考虑如何判断是否能够完全消除。当 时,如果 且 中有超过 个连续的 是显然无解的。否则,我们可以考虑把 左右第一个 ,通过不断操作其中一个,就能把另一个挪到中间位上面。 为偶数时,我们显然能发现我们可以把 劈成左右两边长度都是奇数的部分。分别判断即可。
随便维护一下,复杂度 。
#include<bits/stdc++.h> using namespace std; #define ll long long #define MP make_pair mt19937 rnd(time(0)); const int MAXN=1e6+6; int pre[MAXN],suf[MAXN],a[MAXN],n,m;string s; vector<array<int,2> > ans; bool check(int l,int r){ int m=(l+r)>>1; if(a[m]>1) return true; int p=max(pre[m],l-1),q=min(suf[m],r+1); return q-p-1<(r-l)/2; } void erase(int l,int r){ while(r-l>=3){ ans.push_back({r-1,2}); r-=2; } ans.push_back({l,r-l+1}); } void solve(int l,int r){ int s=0; int m=(l+r)>>1; int p=pre[m],q=suf[m]; if(p!=m){ // do m-p operators s.t. p inthe middle for(int i=1;i<q;i++) s+=a[i]; erase(s+1,s+a[q]); for(int i=1;i<m-p;i++){ s-=a[q-i]; erase(s+1,s+a[q-i]+a[q+i]); } a[q-m+p]+=a[q+m-p]; for(int i=q+m-p+1;i<=r;i++) a[i-2*m+2*p]=a[i]; } s=0; for(int i=1;i<p;i++) s+=a[i]; erase(s+1,s+a[p]); for(int i=1;i<=p-l;i++){ s-=a[p-i]; erase(s+1,s+a[p-i]+a[p+i]); } } void output(){ cout<<ans.size()<<'\n'; for(auto i:ans) cout<<i[0]<<' '<<i[1]<<'\n'; } int main(){ ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>n>>s;s=" "+s; for(int i=1;i<=n;i++){ m++;a[m]=1; while(i<n&&s[i+1]==s[i]) a[m]++,i++; } for(int i=1;i<=m;i++) pre[i]=(a[i]>1?i:pre[i-1]); suf[m+1]=m+1; for(int i=m;i>=1;i--) suf[i]=(a[i]>1?i:suf[i+1]); if(m&1){ if(check(1,m)) solve(1,m),output(); else cout<<"-1\n"; }else{ for(int i=1;i<=m;i+=2) if(check(1,i)&&check(i+1,m)){ solve(i+1,m);solve(1,i);output(); return 0; } cout<<"-1\n"; } return 0; }
- 1
信息
- ID
- 7132
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者