2016年ACM/ICPC北京赛区 I题(思维 二项式展开)

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5698

题意:给你一个只由0~9字符构成的长度为n(n<=50000)的字符串a,

定义,求对于每个i(i=1,2,...,n) ,输出。答案对1e9+7取模。

由题意,存在表达式


令s[i]为a[i]的前缀和,再进行二项式展开,则有

因此

组合数可以O(k^2)预处理,s[i]可以O(n)预处理,s[i]^k可以O(n*k)预处理,s[i]^k的前缀和也可以O(n*k)预处理,对于每个i,O(k)计算ans[i],总复杂度为O(n*k)

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mo=1e9+7;
const int maxn=50010;
ll s[maxn],ss[maxn][101],sss[maxn][101];
ll c[101][101],n,k;
char a[maxn];
void init()
{
    for(int i=0;i<=100;i++)
    {
        c[i][0]=1;
        for(int j=1;j<=i;j++)
        {
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
        }
    }
}
int main()
{
    init();
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&n,&k);
        getchar();
        scanf("%s",a+1);
        s[0]=0;
        for(ll i=1;i<=n;i++)
        {
            s[i]=s[i-1]+(a[i]&15);
        }
        for(ll i=1;i<=n;i++)
        {
            ss[i][0]=1;
            sss[i][0]=0;
            for(ll j=1;j<=k;j++)
            {
                ss[i][j]=(ss[i][j-1]*s[i])%mo;
                sss[i][j]=(sss[i-1][j]+ss[i][j])%mo;
            }
        }
        for(ll i=1;i<=n;i++)
        {
            ll ans=i*c[k][0]%mo*ss[i][k]%mo;
            ll tmp;
            for(ll j=1;j<=k;j++)
            {
                if(j&1) tmp=-sss[i-1][j];
                else tmp=sss[i-1][j];
                ans=(ans+(c[k][j]*ss[i][k-j]%mo*tmp)%mo)%mo;
            }
            ans=(ans+mo)%mo;
            printf("%lld%c",ans,i==n?'\n':' ');
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/LSD20164388/article/details/82940304
今日推荐