[原]Wannafly挑战赛5 D题题解 数学

楚东方 17/12/08 23:53:41

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

给定一个小写字母字符串T

求有多少长度为m的小写字母字符串S满足,T是S的一个子序列(不需要连续)

输入描述:

第一行一个字符串T
第二行一个正整数m

输出描述:

输出答案对109+7取模的值
示例1

输入

a
2

输出

51

说明

长度为2的里面有a的串有51种

备注:

1<=|T|,m<=105

思路:

想法比较敲妙,为了避免重复清空发生,例如 a_ _ b_ _ c_ _ _ _,需保证a,b之间的不能为b ;b,c之间的不能为c 依次类推

在m个里面选择n个位置,枚举最后一个位置, 最后一个位置之前的只需放25种,最后往后的需放26种

需要用逆元


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1e9+7;
ll f[100005];

ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p%MOD;p=p*p%MOD;q>>=1;}return f%MOD;}

//模乘法的逆
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(!b)
    {
        d=a;x=1;y=0;
    }
    else
    {
         ex_gcd(b,a%b,d,y,x);
         y-=(a/b)*x;
    }
}
ll inverse(ll a,ll n)
{
    ll d,x,y;
    ex_gcd(a,n,d,x,y);
    return d==1?(x+n)%n:-1;
}



string s;
ll n,m;
int main()
{
//    freopen("data.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin >> s;
    cin >> m;
    n = s.size();
    if(m<n)
    {
        cout << 0<<endl;
        return 0;
    }

    ll ans  = 0;
    f[0]=1;


    ll tx;
    for(int i=n;i<=m;i++)
    {
        if(i==n)
        {
            tx=1;
        }
        else
        {
            ll tm =  n-1;
            ll tn =  i-2;
            tx = f[i-n-1] *(tn+1) %MOD;
            tx *= inverse(tn+1-tm,MOD);
            tx%=MOD;
            f[i-n]=tx;
        }

        ll x  = i-n;
        ll y  = m-i;

        tx*=qpow(25,x);
        tx%=MOD;
        tx*=qpow(26,y);
        tx%=MOD;


        ans += tx;
        ans%=MOD;
    }
    cout << ans<<endl;
    return 0;
}






























作者:chudongfang2015 发表于2017/12/8 23:53:41 原文链接
阅读:0 评论:0 查看评论