双倍经验题
manacher/palindromic tree
对于manacher的话显然回文串的长度最多只有n种,对于每个奇数长度的位置显然长度为1,3,5.....r[i]的串的个数都+1,区间加减什么的差分一下前缀和搞一搞就好了
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; #define rep(i,l,r) for(int i=l;i<=r;i++) #define per(i,r,l) for(int i=r;i>=l;i--) #define mmt(a,v) memset(a,v,sizeof(a)) const int N=1000000+5; const int p=19930726; typedef long long ll; char s[N<<1],t[N]; int r[N<<1],n; ll cnt[N],k; void manacher(){ int m=n<<1|1; rep(i,1,m) if(i&1)s[i]='#'; else s[i]=t[i>>1]; int id,mx=0; rep(i,1,m){ if(mx>i)r[i]=min(mx-i,r[2*id-i]); else r[i]=1; while(i-r[i]>=1&&i+r[i]<=m&&s[i-r[i]]==s[i+r[i]])r[i]++; if(~r[i]&1)cnt[(r[i]>>1)]++; if(i+r[i]>mx)mx=i+r[i],id=i; } } ll qmul(ll a,ll b){ ll ans=1; for(;b;b>>=1,a=a*a%p)if(b&1)ans=ans*a%p; return ans; } int solve(){ manacher(); ll ans=1; per(i,n,1){ cnt[i]+=cnt[i+1]; if(cnt[i]<=k){ k-=cnt[i]; (ans*=qmul(2*i-1,cnt[i]))%=p; }else (ans*=qmul(2*i-1,k))%=p,k=0; if(!k)return ans; } return -1; } int main(){ //freopen("a.in","r",stdin); scanf("%d%lld",&n,&k); scanf("%s",t+1); printf("%d\n",solve()); return 0; }
回文树就是裸题了,lazytag打一打,逆序更新一下就好了(由于我比较懒就没基数排序QAQ结果就是nlogn了,好像慢了5倍左右)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; #define rep(i,l,r) for(int i=l;i<=r;i++) #define per(i,r,l) for(int i=r;i>=l;i--) #define mmt(a,v) memset(a,v,sizeof(a)) const int N=1000000+5; const int p=19930726; typedef long long ll; ll qmul(ll a,ll b){ ll ans=1; for(;b;b>>=1,a=a*a%p)if(b&1)ans=ans*a%p; return ans; } struct Node{ int len,suf,ch[26]; ll sum; bool operator < (const Node &x)const{ return len>x.len; } }tr[N]; int last,node; void init(){last=node=2;tr[tr[tr[2].suf=1].suf=1].len=-1;} char s[N]; void add(int i){ int cur=last,c=s[i]-'a'; while(s[i-tr[cur].len-1]!=s[i])cur=tr[cur].suf; if(!tr[cur].ch[c]){ tr[last=++node].len=tr[cur].len+2;tr[cur].ch[c]=last; int tmp=tr[cur].suf; while(s[i-tr[tmp].len-1]!=s[i])tmp=tr[tmp].suf; tr[last].suf=tr[last].len==1?2:tr[tmp].ch[c]; } last=tr[cur].ch[c];tr[last].sum++; } int n; ll k; int solve(){ ll ans=1; rep(i,1,node){ if(tr[i].len<=0)continue; if(~tr[i].len&1)continue; if(tr[i].sum<=k) (ans*=qmul(tr[i].len,tr[i].sum))%=p,k-=tr[i].sum; else (ans*=qmul(tr[i].len,k))%=p,k=0; if(!k)return ans; } return -1; } int main(){ //freopen("a.in","r",stdin); scanf("%d%lld %s",&n,&k,s+1); init(); rep(i,1,n)add(i); //rep(i,1,node)printf("%d\n",tr[i].len); per(i,node,1)tr[tr[i].suf].sum+=tr[i].sum; sort(tr+1,tr+1+node); printf("%d\n",solve()); return 0; }