不来也不去的一只失忆蝴蝶

曾迷途才怕追不上满街赶路人

[arc077f]SS

前言

有趣的字符串题。
我是不是推出了什么和大家看起来不一样实质上一样的东西。

题目大意

定义AA表示两个一样的字符串A接在一起。
定义F(SS)=TT,TT是长度最小的满足条件的字符串且SS是TT的前缀。
给你小写字母串SS,求F10100(SS)的区间[l,r]每个字母出现次数。

有趣

这显然是一道和border相关的题。
然后可以发现只考虑S的变化就行,不需要考虑SS。
先做一遍kmp求出nxt(S)。
我们不妨分类讨论一下。
如果S本身就是一个循环串,容易发现F了10^100次后就是这个循环节无限循环,只需要统计一个循环节内每个字母出现次数即可,最后剩余一点再去统计对应前缀。
如果不是循环串呢?
有一个结论是它永远不会变成循环串。
如果nxt(S)>=(|S|+1)/2,那么我们推一下发现经过一次F变化后nxt反而变小(nxt会变成border长度,可以证明不会更长),然后就转化为nxt(S)<(|S|+1)/2的情况。
那么不妨只讨论nxt(S)<(|S|+1)/2的情况,假如这时串是ABA。其中A是前nxt(S)个字符组成的字符串。
一次变换后会变成ABAAB,nxt变成AB(可以用反证法证明不会更长,否则原串是循环串),假如设cnt1表示A中某字母出现次数,cnt2表示B中某字母出现次数。
那么一次变换|S’|=2*|S|-nxt(S),nxt(S’)=|S|-nxt(S),cnt1’=cnt1+cnt2,cnt2’=cnt1。
于是可以注意到nxt(S)<(|S|+1)/2永远满足,然后可以发现一次变换|S|至少变为原来的1.5倍,因此爆1e18只需要log次。不妨暴力处理出来,就很好求答案了。
可以参考代码实现。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=200000+10;
const ll inf=1000000000000000000;
char s[maxn];
ll len[1000],nt[1000],cnt1[1000][27],cnt2[1000][27],o[27],ans[27];
int nxt[maxn];
int i,j,k,t,n,m,tot,top;
ll l,r;
void kmp(){
    j=0;
    fo(i,2,n){
        while (j&&s[j+1]!=s[i]) j=nxt[j];
        if (s[j+1]==s[i]) j++;
        nxt[i]=j;
    }
}
void work(ll n,int f){
    int i,j;
    fd(i,top,1)
        if (n>=len[i]){
            fo(j,0,25) ans[j]+=f*(cnt1[i][j]*2+cnt2[i][j]);
            n-=len[i];
        }
    if (n>=len[0]){
        fo(j,0,25) ans[j]+=f*o[j];
        n-=len[0];
    }
    fo(i,1,n) ans[s[i]-'a']+=f;
}
void solve(ll n,int f){
    int i,j;
    fo(i,0,25) ans[i]+=(ll)f*(n/tot)*o[i];
    n%=tot;
    fo(i,1,n) ans[s[i]-'a']+=f;
}
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    n/=2;
    kmp();
    if (n%(n-nxt[n])){
        fo(i,1,nxt[n]) cnt1[0][s[i]-'a']++;
        fo(i,nxt[n]+1,n-nxt[n]) cnt2[0][s[i]-'a']++;
        fo(i,1,n) o[s[i]-'a']++;
        len[0]=n;nt[0]=nxt[n];
        if (nxt[n]>=(n+1)/2){
            top++;
            len[top]=len[top-1]*2-nt[top-1];
            nt[top]=len[top-1]-nt[top-1];
            fo(i,1,nt[top]) cnt1[top][s[i]-'a']++;
            fo(i,n-nxt[n]+1,n) cnt2[top][s[i]-'a']++;
        }
        while (len[top]<inf){
            top++;
            len[top]=len[top-1]*2-nt[top-1];
            nt[top]=len[top-1]-nt[top-1];
            fo(i,0,25){
                cnt1[top][i]=cnt1[top-1][i]+cnt2[top-1][i];
                cnt2[top][i]=cnt1[top-1][i];
            }
        }
        scanf("%lld%lld",&l,&r);
        work(r,1);
        work(l-1,-1);
        fo(i,0,25) printf("%lld ",ans[i]);
    }
    else{
        tot=n-nxt[n];
        fo(i,1,tot) o[s[i]-'a']++;
        scanf("%lld%lld",&l,&r);
        solve(r,1);
        solve(l-1,-1);
        fo(i,0,25) printf("%lld ",ans[i]);
    }
}
阅读更多
版权声明:本文是蒟蒻写出来的,神犇转载也要说一声哦! https://blog.csdn.net/WerKeyTom_FTD/article/details/78441483
个人分类: KMP
想对作者说点什么? 我来说一句

ss自用软件

2017年11月13日 1.29MB 下载

LED亮度控制电路的设计

2011年03月01日 517KB 下载

ss搭建教程&脚本

2017年04月05日 4KB 下载

没有更多推荐了,返回首页

不良信息举报

[arc077f]SS

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭