D. String Deletion
题目大意
给你一个字符串,每次操作可以删除一个字符,然后删除这个字符串从头开始最长相同的字符串,问最多可以操作几次
解题思路
(比赛时脑抽,没写出来,又掉了一大波分)
我们可以采用贪心的方法求解,我们把连续相同地字符看作一个联通块,因此这个字符串就是由许多联通块组成的。那么如果最前面的联通块的长度不是1的话,我们就从这个联通快中删除一个字符,然后连通块的数量-1,如果这个连通块长度为1的话,就从他后面的连通块中选取一个长度不为1的进行删除,然后连通块数量-1,如果后面也没有连通块长度大于1的,则直接输出当前连通块数量/2(向上取整)。
注意:如果每次都从当前连通块向后找长度不为1的,就会超时,因此我们可以用一个变量来进行标记,指向当前长度不为的1的连通块
#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; const int maxn=2e5+5; char s[maxn]; struct n { int l,r,flag,len; }node[maxn]; int main() { int t,n; scanf("%d",&t); while(t--) { scanf("%d",&n); scanf("%s",s+1); int l=1; int cnt=0; s[n+1]='#'; for(int i=1;i<=n;i++) { if(s[i]!=s[i+1]) { node[++cnt].l=l; node[cnt].r=i; node[cnt].flag=s[i]; node[cnt].len=i-l+1; l=i+1; } } long long ans=0; int flag=1; int bt=cnt; int i=1; // for(int i=1;i<=cnt;i++) printf("%d ",node[i].len); while(cnt>0) { if(node[flag].len!=1) { ans++; flag++; cnt--; } else{ bool find=false; i=max(i,flag); i=min(i,bt); for(;i<=bt;i++) { if(node[i].len!=1) { find=true; node[i].len--; flag++; ans++; cnt--; break; } } if(!find) { ans+=cnt/2; if(cnt%2) ans++; break; } } } printf("%lld ",ans); } return 0; }