hdu 4426 Palindromic Substring

因为每个串的不同回文子串数目是 O(n) 的,考虑求出不同的子串及其数目,显然回文树可以搞,构建完回文树之后按照最长回文后缀边产生的拓扑序下推标记,查询时直接dfs整棵树求出每个串的value后排序即可。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
const ll md=777777777;
char cz[100010];int n,m,tn,nx[100010][26],px[100010],le[100010],dg[100010],ar[26];ll fr[100010],sm[100010],fg[100010];
struct bi{ll a,b;}xr[100010];
bool bimp(const bi&a,const bi&b){return a.a<b.a;};
void pshd(int v){
    if(px[v]>1)fg[px[v]]+=fg[v],sm[px[v]]+=fg[v];
    fg[v]=0;
};
void _cl(){
    int i,j,t,tn,lst;clr(dg),clr(nx[0]),clr(nx[1]),px[1]=0,le[0]=-1,le[1]=0;
    for(tn=i=1,lst=0;i<=n;++i){
        for(t=cz[i]-'a',j=lst;cz[i]!=cz[i-le[j]-1];j=px[j]);
        if(nx[j][t]){lst=nx[j][t];sm[lst]++,fg[lst]++;}
        else{
            lst=++tn;clr(nx[tn]),le[tn]=le[j]+2,nx[j][t]=tn,sm[tn]=fg[tn]=1;
            for(j=px[j];cz[i]!=cz[i-le[j]-1];j=px[j]);
            px[tn]=le[tn]>1?nx[j][t]:1;if(px[tn]>1)dg[px[tn]]++;
        }
    }
    queue<int>qe;for(i=2;i<=tn;++i)if(!dg[i])qe.push(i);
    for(;!qe.empty();){
        t=qe.front();qe.pop();pshd(t),dg[px[t]]--;
        if(px[t]>1&&!dg[px[t]])qe.push(px[t]);
    }
};
void _clfr(){
    int i;for(fr[0]=1,i=1;i<=100000;++i)
        fr[i]=fr[i-1]*26%md;
};
void dfs(int v,ll x,int d){
    if(d){xr[tn].a=x,xr[tn].b=sm[v];++tn;}
    int i;for(i=0;i<26;++i)if(nx[v][i]){
        dfs(nx[v][i],(x+fr[d]*ar[i])%md,d+1);
    }
};
void cl(){
    int i;ll j,k;scanf("%d %d",&n,&m);scanf("%s",cz+1);
    for(_cl();m;m--){
        for(scanf("%I64d",&k),i=0;i<26;scanf("%d",&ar[i++]));
        tn=0;dfs(0,0,0),dfs(1,0,0);sort(xr,xr+tn,bimp);
        for(i=j=0;;++i){
            j+=xr[i].b;
            if(j>=k){printf("%I64d\n",xr[i].a);break;}
        }
    }
    putchar('\n');
};
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int t;for(_clfr(),scanf("%d",&t);t;t--,cl());
    return 0;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值