BZOJ 2160: 拉拉队排练(回文树)

 

传送门:

  [1]:BZOJ

  [2]:洛谷

 

•题意

  求串 s 中出现的所有奇回文串,并按照长度由大到小排序;

  输出前 k 个奇回文串的乘积 mod 19930726;

  如果奇回文串的个数不足 k 个,输出 -1;

•题解

  将串 s 跑一边回文自动机;

  将求解出的 len,cnt 数组存入一个结构体中并按照 len 由大到小排序;

  将前 k 个奇回文串的长度相乘就行;

  记得用快速幂,并且只要奇回文串的长度乘积;

•Code

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define ll long long
  4 const int MOD=19930726;
  5 const int maxn=1e6+50;
  6  
  7 int n;
  8 ll k;
  9 char s[maxn];
 10  
 11 struct PAM
 12 {
 13     int tot;
 14     int last;
 15     ll cnt[maxn];
 16     ll len[maxn];
 17     int fail[maxn];
 18     int son[maxn][30];
 19  
 20     int newNode(int Len)
 21     {
 22         for(int i=0;i < 30;++i)
 23             son[tot][i]=0;
 24  
 25         len[tot]=Len;
 26         fail[tot]=0;
 27         cnt[tot]=0;
 28  
 29         return tot++;
 30     }
 31     int getFail(int p,int i)
 32     {
 33         while(s[i-len[p]-1] != s[i])
 34             p=fail[p];
 35         return p;
 36     }
 37     void Init()
 38     {
 39         tot=0;
 40         last=0;
 41  
 42         newNode(0);
 43         newNode(-1);
 44  
 45         fail[0]=1;
 46     }
 47     void Count()
 48     {
 49         for(int i=tot-1;i >= 0;--i)
 50             cnt[fail[i]] += cnt[i];
 51     }
 52     void pam()
 53     {
 54         Init();
 55  
 56         for(int i=1;i <= n;++i)
 57         {
 58             s[i]=s[i]-'a'+1;
 59  
 60             int cur=getFail(last,i);
 61  
 62             if(!son[cur][s[i]])
 63             {
 64                 int now=newNode(len[cur]+2);
 65                 fail[now]=son[getFail(fail[cur],i)][s[i]];
 66                 son[cur][s[i]]=now;
 67  
 68             }
 69             cnt[last=son[cur][s[i]]]++;
 70         }
 71         Count();
 72     }
 73 }_pam;
 74 struct Data
 75 {
 76     ll cnt;
 77     ll len;
 78     bool operator < (const Data &obj) const
 79     {
 80         return len > obj.len;
 81     }
 82 }a[maxn];
 83  
 84 ll qPow(ll a,ll b,ll m)
 85 {
 86     ll ans=1;
 87     a %= m;
 88     while(b)
 89     {
 90         if(b&1)
 91             ans=ans*a%m;
 92         a=a*a%m;
 93         b >>= 1;
 94     }
 95     return ans;
 96 }
 97 int main()
 98 {
 99     scanf("%d%lld",&n,&k);
100     scanf("%s",s+1);
101     s[0]='#';
102  
103     _pam.pam();
104  
105     int x=0;
106     for(int i=2;i < _pam.tot;i++)
107         a[++x]=Data{_pam.cnt[i],_pam.len[i]};
108  
109     sort(a+1,a+x+1);
110  
111     int index=1;
112     ll ans=1;
113     while(index <= x)
114     {
115         if(!(a[index].len&1))///坑:如果不是奇回文串,continue
116         {
117             index++;
118             continue;
119         }
120  
121         ll cur=min(k,a[index].cnt);
122  
123         ans *= qPow(a[index++].len,cur,MOD);
124         ans %= MOD;
125         k -= cur;
126  
127         if(k == 0)
128             break;
129     }
130     if(k > 0)
131         ans=-1;
132  
133     printf("%lld\n",ans);
134 }
View Code

 

posted @ 2019-07-31 11:45  HHHyacinth  阅读(177)  评论(0编辑  收藏  举报