LG1659 [国家集训队]拉拉队排练
作者:互联网
拉拉队排练
n个女生从左到右排成一行,每个人手中都举了一个写有26个小写字母中的某一个的牌子
如果连续的一段女生,有奇数个,并且他们手中的牌子所写的字母,从左到右和从右到左读起来一样,那么这一段女生就被称作和谐小群体.
找出所有和谐小群体,并且按照女生的个数降序排序之后,前K个和谐小群体的女生个数的乘积是多少
答案除以19930726的余数
n ≤ 106, k ≤ 1012
题解
学习了一下回文自动机
nianheng的博客
此题将状态将 len 排序后扫一遍就可以了。
时间复杂度\(O(n)\),回文自动机的复杂度分析似乎跟AC自动机一样。
注意写代码的时候新建节点要先处理信息再连边,否则 如果 last=1 的话 fail 可能会连向自己。
#include<bits/stdc++.h>
using namespace std;
template<class T> T read(){
T x=0,w=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*w;
}
template<class T> T read(T&x){
return x=read<T>();
}
#define co const
#define il inline
typedef long long LL;
co int mod=19930726;
il int mul(int a,int b){
return (LL)a*b%mod;
}
il int fpow(int a,int b){
int ans=1;
for(;b;b>>=1,a=mul(a,a))
if(b&1) ans=mul(ans,a);
return ans;
}
co int N=1000000+10;
int last,tot;
struct node{int ch[26],fa,len,siz;}s[N];
char str[N];
int get_fa(int x,int p){
while(str[p-s[x].len-1]!=str[p]) x=s[x].fa;
return x;
}
void extend(int p){
int cur=get_fa(last,p);
int now=s[cur].ch[str[p]-'a'];
if(!now){
now=++tot;
s[now].fa=s[get_fa(s[cur].fa,p)].ch[str[p]-'a'];
s[now].len=s[cur].len+2;
s[cur].ch[str[p]-'a']=now; // edit 1: last=1
}
++s[now].siz;
last=now;
}
il bool operator<(co node&a,co node&b){
return a.len>b.len;
}
int main(){
int n=read<int>();LL K=read<LL>();
scanf("%s",str+1);
last=tot=1;
s[1].len=-1,s[0].fa=s[1].fa=1;
for(int i=1;i<=n;++i) extend(i);
for(int i=tot;i>=2;--i) s[s[i].fa].siz+=s[i].siz;
sort(s+2,s+tot+1);
int ans=1;
for(int i=2;K;++i){
if(i>tot) {puts("-1");return 0;}
if(~s[i].len&1) continue;
if(s[i].siz<K){
K-=s[i].siz;
ans=mul(ans,fpow(s[i].len,s[i].siz));
}
else{
ans=mul(ans,fpow(s[i].len,K));
K=0;
}
}
printf("%d\n",ans);
return 0;
}
标签:return,int,拉拉队,len,fa,LG1659,str,now,国家集训队 来源: https://www.cnblogs.com/autoint/p/11415307.html