连山科技程序设计大赛(J. 金色传说(动态规划))

J. 金色传说

龙老师获得了一个不寻常的计算器,因为这个道具的品质是金色传说。它除了在按 666 时可以发出声音以外,还可以输入一个算式并计算出它的结果。金色传说计算器的显示屏上只有 n 个可以显示的位置,而且只有 0⋯9 十个数字键和两个运算符键+、-共 12 个按键可以按,连=都没有,所以必须输入一个 n 位的合法算式,它才会自动计算出该算式的结果。

我们定义合法的算式为一个长度恰好为 n 的字符串,其中字符串只包含数字 0⋯9 和运算符+、-,同时不允许算式第一个或最后一个位置出现运算符,也不允许同时有两个运算符相邻。算式的计算结果是对该字符串模拟十进制加减法运算得到的结果,只包含数字的算式其计算结果等于它本身。如果金色传说计算器的输入不是一个合法的算式,那么它就不能得到任何计算结果。例如,在 n=6 时,1+2+3、+12345、23+45+和123±4都不是合法的算式,而123456和0+0+00都是合法的算式。注意,前导零是允许在算式中出现的。

龙老师一个个地数出了计算器的显示位置数 n。他想知道,如果把所有的合法的算式全都都输入一次,金色传说计算器输出的所有计算结果之和是多少?计算结果的总和可能很大,请输出它对 998244353 取模之后的答案。

Input

第一行输入一个正整数 T (1≤T≤100),表示数据组数。

接下来 T 组数据,每组数据输入一个正整数 n (1≤n≤5×105),表示金色传说计算器的显示位。

Output

对于每组数据,请输出一个非负整数,表示所有计算结果之和取模 998244353 之后的答案,注意换行。

Example
input

5
1
2
3
4
5

output

45
4950
500400
50103000
19816235

Note

当 n=1 时,共有 0,1,⋯,9 共 10 个合法算式,它们的结果之和是 45。

当 n=2 时,共有 00,⋯,99 共 100 个合法算式,它们的结果之和是 4950。

当 n=3 时,000,⋯,999 是合法的算式,当然与形如A+B和A-B的算式也都是合法算式,它们的结果之和是 500400。

solution

一个重要的结论是——对于统计答案,只有整个串中的第一个数字对答案是有贡献的。
证明如下:
任意只带一个运算符的串,不妨设为 a+b。其中 a、b 都是纯数字。那么存在一个 a-b 把 b 对答案的贡献抵消了。所以对答案有贡献的只有 a 部分。任意只带两个运算符的串,不妨设为 a+b+c。其中 a、b、c
都是纯数字。那么存在其他三个串 a+b-c,a-b+c,a-b-c,不难发现 b、c 各被加减两次,恰好对答案的贡献抵消了。所以对答案有贡献的还是只有 a 部分。
知道了只有第一个出现的数对答案有贡献,那么可以枚举第一个出现运算符的位置。以这个运算符为界,前面是第一个出现的数字,后面是一个任意的算式,两者是相互独立的。记所有的 k 位数字的和为 sum[k],记
所有长度为 k 算式的个数为 num[k],那么答案即为

sum[n]+ 2* ∑ i = 2 n − 1 s u m [ i − 1 ] ∗ s u m [ n − i ] \sum_{i=2}^{n-1}{sum[i-1]*sum[n-i]} i=2n1sum[i1]sum[ni]

前项为不出现运算符的情况,后项为出现运算符时枚举第一个运算符的位置。由等差数列求和可知

sum[i]= ( 0 + 1 0 i − 1 ) ∗ 1 0 i 2 \frac{(0+10^i-1)*10^i}{2} 2(0+10i1)10i

而 num[k] 部分可以考虑同样的思路,即枚举第一个运算符位置,则

sum[k]=2* ∑ i = 2 k − 1 1 0 i − 1 ∗ n u m [ k − i ] \sum_{i=2}^{k-1}{10^{i-1}*num[k-i]} i=2k110i1num[ki]

num[k+1]=2* ∑ i = 2 k 1 0 i − 1 ∗ n u m [ k + 1 − i ] \sum_{i=2}^{k}{10^{i-1}*num[k+1-i]} i=2k10i1num[k+1i]

令 j = i -1 ,则

num[k+1]=2* ∑ j = 1 k − 1 1 0 j ∗ n u m [ k − j ] \sum_{j=1}^{k-1}{10^j*num[k-j]} j=1k110jnum[kj]

令 j = i ,则

num[k]=2* ∑ j = 2 k − 1 1 0 j − 1 ∗ n u m [ k − j ] \sum_{j=2}^{k-1}{10^{j-1}*num[k-j]} j=2k110j1num[kj]

联立。
不难发现只有 j = 1 时需要特别计算,其他部分可以直接从num[k] 得到,即
num[k + 1] = 10 · num[k] + 20 · num[k F 1],
线性递推即可。
时间复杂度 O(n)。

#include <bits/stdc++.h>
using namespace std;
const long long mod=998244353;
typedef long long ll;
ll num[500005];
ll sum[500005];

int main()
{
    int T;
    cin>>T;
    ll inv=499122177;  //2的mod-2次幂
    ll power=1;
    for(int i=1;i<=500000;i++){
            power=power*10%mod;
      sum[i]=((power-1)*power)%mod*inv%mod;  //除法取模
    }
     num[1]=10;
     num[2]=100;
     for(int i=3;i<=500000;i++){
        num[i]=(10*num[i-1]+20*num[i-2])%mod;
     }
    while (T--)
    {
       int n;
       cin>>n;
       ll Sum=0;
       for(int i=2;i<n;i++){
          Sum+=2*(sum[i-1]*num[n-i])%mod;
       }
       Sum=(Sum+sum[n])%mod;
       cout<<Sum<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值