Hihocoder 1430 A Boring Problem (数论)

来源:互联网 发布:mac上安装apt get 编辑:程序博客网 时间:2024/06/05 21:10

Problem

对于数字串 S ,S[l] 表示串 S 的第 l 个数字( l 从 1 开始标记)。

F(j, i)=(Σil=jS[l])

对于每个 i ,求 Σij=1F(j, i)

限制条件

T ≤ 5

N ≤ 50000

k ≤ 100

解题思路

模拟暴力求每一项的结果:

第一项:(S1)k

第二项:(S1+S2)k+(S2)k

第三项:(S1+S2+S3)k+(S2+S3)k+(S3)k

这样的复杂度将达到 O(N2×logK) ,即使通过预处理出 45 万数(最大前缀和)的 K 次结果,复杂度仍将有 O(N2)

考虑前缀和表示结果

第一项:(Pre1Pre0)k

第二项:(Pre2pre0)k+(Pre2Pre1)k

第三项:(Pre3Pre0)k+(Pre3Pre1)k+(Pre3Pre2)k

将其展开:

第一项:C0kPrek1+C1kPrek11(Pre0)1+...+CkkPre01(Pre0)k

第二项:C0kPrek2+C1kPrek12(Pre0Pre1)1+...+CkkPre02(Pre0Pre1)k

第三项:C0kPrek3+C1kPrek13(Pre0Pre1Pre2)1+...+CkkPre03(Pre0Pre1Pre2)k

Pre0+Pre1+...+Prej 记作 PPrevj ,预处理出所有的 PPrevj

对每一项乘法求解的复杂度为 O(K) 。整体复杂度为 O(N×K)

代码

#include<bits/stdc++.h>using namespace std;const int mod = 1e9 + 7;int T, N, k;long long pre[50010][110], pprev[50010][110], c[110][110];char s[50010];void init(){    c[0][0]=1;    for(int i=1;i<=100;++i){        c[i][0]=c[i][i]=1;        for(int j=1;j<i;++j)            (c[i][j]=c[i-1][j-1]+c[i-1][j]) %= mod;    }}int main(){       init();    scanf("%d", &T);    while(T--)    {        scanf("%d %d %s", &N, &k, s+1);        for(int i=1;i<=N;i++)        {            pre[i][0] = 1;            pre[i][1] = pre[i-1][1] + s[i]-'0';            for(int m=2;m<=k;m++)                pre[i][m] = (pre[i][m-1] * pre[i][1]) % mod;        }        for(int i=1;i<=N;i++)        {            for(int m=0;m<=k;m++)                (pprev[i][m] = pprev[i-1][m] + (m%2?-1:1) * pre[i][m]) %= mod;        }        for(int i=1;i<=N;i++)        {            long long ans = 0;            for(int m=0;m<=k;m++)            {                ans += c[k][m] * pre[i][k-m] % mod * pprev[i-1][m] % mod + mod;                ans %= mod;             }            printf("%lld%c", ans, i==N?'\n':' ');        }    }}
原创粉丝点击