prefix free code

其实总的感觉也不是很难

就是昨天看到第二题就放弃了

简单来说就是组合数学一点点+字典树一点点

像是一个数位dp

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(ll i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

#define ll long long 
ll n,k;
const int maxn=1000005,mod=1e9+7;
ll tot,tr[maxn][27],ed[maxn],cnt[maxn];
char s[maxn];

inline void insert()
{
    ll len=strlen(s+1);
    ll rt=0;
    inc(i,1,len)
    {
        if(!tr[rt][s[i]-'a'])
            tr[rt][s[i]-'a']=++tot;
        rt=tr[rt][s[i]-'a'];
    }
    ed[rt]=1;
    ++cnt[rt];
}

inline void dfs(ll rt)
{

    if(ed[rt])re;
    inc(i,0,25)
    if(tr[rt][i])
    {
        dfs(tr[rt][i]);
        cnt[rt]+=cnt[tr[rt][i]];
    }    
    
}
ll slen,st=1;
ll jc[maxn],jcinv[maxn],ans,Ans,CNT;

inline void find(ll rt)
{
    
    if(ed[rt])
    {
        Ans=(Ans+jc[n-CNT]*jcinv[n-k]%mod*ans%mod)%mod;
        cnt[rt]--;
        re ; 
    }
    ll x=s[st]-'a';
    inc(i,0,25)
    if(i<x)
    {
        if(tr[rt][i])ans+=cnt[tr[rt][i]];
               //因为下标从0开始
    }
    else 
    {
        ++st;
        find(tr[rt][x]);
        cnt[rt]--;
        re ;
    }

}

inline void Get_jc()
{
    jcinv[0]=jcinv[1]=jc[1]=jc[0]=1; 
    inc(i,2,n)
    {
        jc[i]=jc[i-1]*i%mod;
        jcinv[i]=(mod-mod/i)*jcinv[mod%i]%mod;
    }
    inc(i,2,n)jcinv[i]=jcinv[i-1]*jcinv[i]%mod;
}

int main()
{
    freopen("in.txt","r",stdin);
    rd(n),rd(k);
    inc(i,1,n)
    {
        scanf("%s",s+1);
        insert();
    }
    
    dfs(0);
    
    Get_jc();
    
    scanf("%s",s+1);
    while(CNT<k)
    {
        ++CNT;
        ans=0;
        find(0);
    }    
    
    printf("%lld",(Ans+1)%mod);
    re 0;
}          

猜你喜欢

转载自www.cnblogs.com/lsyyy/p/11606558.html