金色传说(dp 数学)

原题: http://fastvj.rainng.com/problem/Gym-102174J

题意:

n长度的所有只有±号的式子的结果之和

解析:

x+b和x-b对应,显然任意一个带有符号的式子找得到一个相反符号的式子,所以只需要累加所有式子的第一个数字即可。

用dp[3]表示后半部分长度为3的方案数(+00、-01、+19),这个dp转移很简单:区分最后一个位置是符号还是数字,两种都可以加数字,但是只有最后为数字才可以加符号。

再看下面递推式:
在这里插入图片描述
一位数后面带两个位置的情况(第三列第一个)为 9 10 / 2 d p [ 2 ] 9*10/2*dp[2] ,到了n=4时,变成了 99 100 / 2 d p [ 2 ] 99*100/2*dp[2] 。对前式扩大100倍得: 90 100 / 2 d p [ 2 ] 90*100/2*dp[2] ,差了 9 100 / 2 d p [ 2 ] 9*100/2*dp[2]
而两位数带两个位置的情况的改变为: 99 100 / 2 d p [ 2 ] 999 1000 / 2 d p [ 2 ] 99*100/2*dp[2]\to 999*1000/2*dp[2] ,乘100后差了 9 1000 / 2 d p [ 2 ] 9*1000/2*dp[2]

a n s [ i ] ans[i] 表示i长度的答案,sum代表还差的部分。
那么 a n s [ i ] = a n s [ i 1 ] 100 + s u m , s u m = s u m 10 ans[i]=ans[i-1]*100+sum,sum=sum*10
还要加上新的部分: a n s [ i ] + = 9 10 / 2 d p [ i 1 ] , s u m + = 9 100 / 2 d p [ i 1 ] ans[i]+=9*10/2*dp[i-1],sum+=9*100/2*dp[i-1]

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn=500009;
const LL mod=998244353;
LL ans[maxn];
LL dp[maxn][2];
void init(){//0 最后是符号
    dp[0][0]=dp[0][1]=1;
    dp[1][0]=2;dp[1][1]=0;
    for(int i=2;i<=5e5;i++){
        dp[i][1]=(dp[i-1][0]+dp[i-1][1])*10%mod;
        dp[i][0]=dp[i-1][1]*2%mod;
    }
    ans[1]=45,ans[2]=4950,ans[3]=500400;
    LL sum=(90000/2+900/2*dp[2][1])%mod;
    for(int i=4;i<=5e5;i++){
        ans[i]=(ans[i-1]*100+sum)%mod;
        sum=sum*10%mod;
        ans[i]=(ans[i]+45*dp[i-1][1])%mod;
        sum=(sum+450*dp[i-1][1])%mod;
    }
}

int main(){
    init();
    int t;scanf("%d",&t);
    while(t--){
        int n;scanf("%d",&n);
        printf("%lld\n",ans[n]);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/89816275