【ARC077F】SS

Description

     若是某個串能夠由兩個同樣的串先後鏈接獲得,咱們就稱之爲「偶串」。好比說「xyzxyz」和「aaaaaa」是偶串,而「ababab」和「xyzxy」則不是偶串。    ​   對於一個非空串$S$,咱們定義$f(S)$是在$S$後面添加一些字符獲得的最短偶串。好比$f($'abaaba'$)=$'abaababaab'。容易證實,對於一個非空串$S$,$f(S)$是惟一的 。    ​   如今給定一個由小寫英文字母構成的偶串$S$,你須要求出$f^{10^{100}}(S)$,並統計計算結果的第$l$個字符到第$r$個字符中,每一個字母出現了多少次 。    ​   其中,$f^{10^{100}}(S)$是指$f(f(f(...f(S)...)))$,式子中共有$10^{100}$個$f$ 。         c++

Solution

   ​   打表找規律。從整個串來尋找規律看不出什麼,反而是分別考慮兩半的變化比較有效。    ​   咱們稱$T$爲$S$的"Border",當且僅當$S$做爲$T$的循環串的前綴出現,且$T$長度最小。    ​   現有輸入串$SS$,令$S$的"Border"爲$T$,則會發現: $$ SS\rightarrow (ST)(ST)\rightarrow (STS)(STS)\rightarrow(STSST)(STSST)... $$ ​   因爲操做次數過多,只考慮前半部分的變化,就能回答全部詢問: $$ S\rightarrow ST\rightarrow STS\rightarrow STSST\rightarrow STSSTSTS $$ ​   咱們發現,從第三個串開始,每個串$i$,都是由串$i-1$+串$i-2$得來。姑且稱它們爲$\text{fib}$串。    ​   特別地:若$|S|-|T|$整除$|S|$,則變化爲 $$ S\rightarrow ST\rightarrow STT\rightarrow STTT... $$ ​   特判掉這種狀況。    ​   記$len_i$爲第$i$個$\text{fib}$串的長度,$g_{i,j}$爲第$i$個$\text{fib}$串中$j$字符出現了多少次。因爲$\text{fib}$在第85項左右就已經超出了$1e18$,所以咱們能夠暴力計算出這兩個數組。    ​   對答案差分,假設要求$1...r$中,每一個字符的出現次數。    ​   有結論是,只要有$len_{x_1}+len_{x_2}+...+len_{x_k}=r$,且$len_{x_1}>len_{x_2}>...>len_{x_k}$,則$1...r$這個字符串就能夠用$x_1,x_2,...,x_k$這$k$個$\text{fib}$串首尾相接獲得。    ​   因此對於詢問咱們從大到小枚舉$\text{fib}$串累加每一個字符的答案。最後可能會剩餘必定長度沒法消去,但剩餘的長度必定不超過$|S|$(在$\text{fib}$串中甚至沒有組成一個元素$S$),且是$S$的一個前綴,額外計算上這些部分便可。    ​     數組

Code

  

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=200005;
int n,up,nex[N],type;
char str[N];
int pre[N][26];
ll l,r,cut,len[100],ans[26];
ll f[100][26];
void readData(){
	scanf("%s%lld%lld",str+1,&l,&r);
	n=strlen(str+1);
	n>>=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<26;j++) pre[i][j]=pre[i-1][j];
		pre[i][str[i]-'a']++;
	}
}
void getNex(){
	nex[1]=0;
	for(int i=2,j;i<=n;i++){
		j=nex[i-1];
		while(j&&str[j+1]!=str[i]) j=nex[j];
		nex[i]=(str[j+1]==str[i])?j+1:0;
	}
}
void preWork(){
	len[1]=n;
	for(int i=1;i<=n;i++){
		f[1][str[i]-'a']++;
		f[2][str[i]-'a']++;
	}
	len[2]=n+cut;
	for(int i=0;i<26;i++) 
		f[2][i]+=pre[cut][i];
	for(int i=3;;i++){
		for(int j=0;j<26;j++) f[i][j]=f[i-2][j]+f[i-1][j];
		len[i]=len[i-2]+len[i-1];
		if(len[i]>1e18){
			up=i;
			break;
		}
	}
}
void calc1(ll m,ll a){
	if(m<=0) return;
	ll t=m/cut;
	for(int i=0;i<26;i++) ans[i]+=a*t*pre[cut][i];
	t=m%cut;		
	for(int i=0;i<26;i++) ans[i]+=a*pre[t][i];
}
void calc2(ll m,ll a){
	for(int i=up;i>=1;i--)
		if(len[i]<=m){
			m-=len[i];
			for(int j=0;j<26;j++) ans[j]+=a*f[i][j];
		}
	for(int j=0;j<26;j++) ans[j]+=a*pre[m][j];
}
int main(){
	readData();
	getNex();
	cut=n-nex[n];
	if(n%cut==0){
		calc1(r,1);
		calc1(l-1,-1);
	}
	else{
		preWork();
		calc2(r,1);
		calc2(l-1,-1);
	}
	for(int i=0;i<26;i++) printf("%lld ",ans[i]);
	return 0;
}
相關文章
相關標籤/搜索