1. 程式人生 > >BZOJ2160 拉拉隊排練題解(manacher)

BZOJ2160 拉拉隊排練題解(manacher)

題目:BZOJ2160.
題目大意:給定一個字串,求它所有長度為奇數的迴文子串中,前k小的長度乘積.若數量超過k輸出-1.

一看就是道manacher裸題,由於長度要求為奇數,所以就不需要在字串中間插入奇奇怪怪的字元啦,只需要在兩邊插入不一樣的字元就可以了.

我們再設一個數組cnt[i]表示長度為i的迴文子串有多少個,那麼每得到一個新的最長迴文子串長度pal[i]我們就可以將1~pal[i]的所有cnt值都加1,但是這樣太慢了所以我們差分一下.

最後我們從1開始列舉,每次加2.當列舉到i時得到的貢獻為 i

c n t [ i ] i^{cnt[i]} ,快速冪搞一下就可以了.

程式碼如下:

#include<bits/stdc++.h>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=1000000;
const LL mod=19930726;

int pal[N+9];

void manacher(char *s,int len){
  s[len+1]='#';
  int p=0,r=0;
  pal[0]=1;
  for (int i=1;i<=len;++i){
  	pal[i]=i<
r?min(pal[2*p-i],r-i):1; while (s[i+pal[i]]==s[i-pal[i]]) ++pal[i]; if (i+pal[i]>r) r=i+pal[i],p=i; } } int cnt[N+9]; LL power(LL a,LL k){ LL s=1; for (;k;k>>=1,a=a*a%mod) if (k&1) s=s*a%mod; return s; } char c[N+9]; int n; LL k,ans=1; void js(){ for (int i=1;i<=n;++i) ++cnt[1],--cnt[pal[i]<<1]; for (int i=1;i<=n;++i) cnt[i]+=cnt[i-1]; for (int i=n;i>=1;--i){ if (i&1^1) continue; if (cnt[i]>=k){ ans=ans*power(LL(i),k)%mod;k=0; break; }else ans=ans*power(LL(i),LL(cnt[i]))%mod,k-=LL(cnt[i]); } if (k) ans=-1LL; } Abigail into(){ scanf("%d%lld",&n,&k); scanf("%s",c+1); } Abigail work(){ manacher(c,n); js(); } Abigail outo(){ printf("%lld",ans); } int main(){ into(); work(); outo(); return 0; }