求助S组T2的正确性
  • 板块学术版
  • 楼主Hiiragi_Utena
  • 当前回复2
  • 已保存回复2
  • 发布时间2023/10/23 22:17
  • 上次更新2023/11/2 11:38:36
查看原帖
求助S组T2的正确性
384596
Hiiragi_Utena楼主2023/10/23 22:17

我的做法:只需求出从任意一个点 ii 开始走到哪会第一次全消完,记为 nxtinxt_i。

在暴力模拟栈求出 nxtinxt_i 的过程中,还可以顺便把这个过程中所有入栈操作的点的 nxtnxt 求出来。于是,就可以从 11 开始扫到 nn,每遇到一个没有求出 nxtnxt 的点就用栈模拟一遍。

但是这样时间复杂度不对,于是加入了优化:模拟栈的时候,若某个点 jj 的操作为入栈,并且 nxtjnxt_j 之前已经求出,那么跳过 [j,nxtj][j,nxt_j] 这一段。

我认为这样做的时间复杂度是 O(26n)O(26n) 的(并且通过了洛谷、核桃、云斗上的数据),但是不会证明。希望大佬能来帮忙看看。

代码如下:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
const int maxn=2000005;
int n,nxt[maxn],st[maxn],bl[maxn],top;
char str[maxn];
long long ans;
void ct(int x){
    top=0;
    for(;x<=n;++x){
        if(top&&str[st[top]]==str[x]){
            nxt[st[top]]=x;
            top--;
        }
        else{
            if(nxt[x]!=-1){
                if(nxt[x]==0)break;
                x=nxt[x];
                continue;
            }
            st[++top]=x;
        }
        if(top==0)break;
    }
    for(int i=1;i<=top;++i)nxt[st[i]]=0;
}
signed main(){
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    n=read();
    scanf("%s",str+1);
    for(int i=1;i<=n;++i)nxt[i]=-1;
    for(int i=1;i<=n;++i)if(nxt[i]==-1)ct(i);
    for(int i=1;i<=n;++i)if(!bl[i]){
        int tmp=0;
        for(int j=i;j<=n;){
            bl[j]=1;
            j=nxt[j];
            if(!j)break;
            ++tmp;
            ++j;
        }
        //printf("%d %d\n",i,tmp);
        ans+=(long long)tmp*(tmp+1)/2;
    }
    printf("%lld",ans);
    return 0;
}
2023/10/23 22:17
加载中...