20200507省選模擬賽A(序列自動機+重鏈剖分+鏈上倍增)

 

 

 

題解

好題

其實序列自動機也不是什麼高級的東西

但是重鏈剖分+鏈上倍增基本上就很難想得到了

還有巧妙的輸出方案的方法:先輸出後面再輸出前面,如果夠了就return

官方題解已經講得很清楚了

注意要先把所有的f初始化爲1,表示只選擇它自己的方案

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 300005
#define LOG 18
#define LL long long
const LL inf=0x3f3f3f3f3f3f3f3fll;
int n,m,ch[N][26],len,tp;
char S[N],a[N];
LL f[N],k;
struct node{
	int p;LL s;
	node(){}
	node(int x,LL y){p=x;s=y;}
	node operator + (const node &b)const{
		return node(b.p,min(s+b.s,inf));
	}
}nxt[N][LOG+2];
void print(int x,int i)
{
	if(tp==len) return;
	if(!i){S[++tp]=a[nxt[x][0].p];return;}
	print(nxt[x][i-1].p,i-1);
	print(x,i-1);
}
void solve(int x)
{
	if(k==1) return;
	bool vis[20]={0};
	int pos[20],i,y;
	for(i=LOG;i>=0;i--){
		if(k>nxt[x][i].s&&k-nxt[x][i].s<=f[nxt[x][i].p]){
			vis[i]=1;
			pos[i]=x;
			k-=nxt[x][i].s;
			x=nxt[x][i].p;
		}
	}
	if(k>1){
		k--;
		for(i=0;i<26;i++){
			y=ch[x][i];
			if(k>f[y])k-=f[y];
			else{solve(y);if(tp<len)S[++tp]='a'+i;break;}
		}
	}
	for(i=0;i<=LOG;i++)
		if(vis[i])print(pos[i],i);
}
int main()
{
	int i,j;
	scanf("%s%d",a+1,&m);
	n=strlen(a+1);
	for(i=0;i<26;i++)ch[n][i]=n+1;
	f[n]=1;
	nxt[n][0]=node(n+1,1);
	nxt[n+1][0]=node(n+1,0);
	for(i=n-1;i>=0;i--){
		memcpy(ch[i],ch[i+1],sizeof(ch[i+1]));
		ch[i][a[i+1]-'a']=i+1;
		f[i]=1; 
		for(j=0;j<26;j++){
			f[i]+=f[ch[i][j]];
			if(f[i]>=inf){f[i]=inf;break;}
		}
		int p=0;
		for(j=0;j<26;j++)if(f[ch[i][j]]>f[ch[i][p]])p=j;
		LL s=1;
		for(j=0;j<p;j++){
			s+=f[ch[i][j]];
			if(s>=inf){s=inf;break;}
		}
		nxt[i][0]=node(ch[i][p],s);
	}
	for(j=1;j<=18;j++)
		for(i=0;i<=n+1;i++)
			nxt[i][j]=nxt[i][j-1]+nxt[nxt[i][j-1].p][j-1];
	while(m--){
		scanf("%lld%d",&k,&len);k++;
		if(k>f[0]){puts("-1");continue;}
		tp=0;solve(0);
		for(i=tp;i>=1;i--)
			printf("%c",S[i]);
		printf("\n");
	}
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章