金色传说

参考于:xls tql

若存在a+b,那么一定存在一个a-b,两者求和,2*a,所以对于每个长度为n和合法式子,只需对每个式子第一个 +/- 前面数字求和,所以需要统计 + / - 号前面的a出现多少次。

假设第一个 + / - 前面是一个长度为i的数字,那么 +  / -  号后面有 n - i - 1位,每个长度为i的数字出现次数 = 2(正负两种情况) * 长度为 n - i -1 合法式子的种数。 因为每个长度为 i 的数字出现次数相同,所以先对长度为 i 的数字求和,前导0也算,用等差数列求和公式(1 + (10 ^ i - 1))*(10 ^ i - 1) / 2 。sum += 长度为i的数字总和 * 2 * 长度为 n - i -1 合法式子的种数。现在只需要求长度为 n - i -1 合法式子的种数。

dp[i]表示长度为i合法式子的种数,

长度为i合法式子有两种来源,

  1. 在长度为i-1合法式子后面添加一个数字
  2. 在长度为i-2合法式子后面添加一个符号和一个数字

所以 dp[i] = dp[i-1] * 10 + dp[i-2] *2 *10

 

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 100;
#define mod 998244353
typedef long long ll;

int t,n;
ll d[N], dp[N];
int main(){
	d[0] = 0;
	d[1] = 45; //所有长度小于等于i数字的和 
	ll p=10;
	for(int i = 2; i <= 5e5; i++){
		p = p * 10 % mod;
		d[i] = p * (p - 1) / 2 % mod;//长度为i的序列和=(1+10^i-1)*(10^i-1)/2 
	}
	dp[0] = 0;
	dp[1] = 10; //长度为i的合法数字列的数量 
	for(int i = 2; i <= 5e5; i++) {
		dp[i] = (dp[i-1] * 10 % mod + dp[i-2] * 20 %mod) %mod;
		//长度为i的合法序列可以由 长度i-1的合法序列加一个数字得到
		//也可以由长度为i-2的合法序列加上一个符号和数字得到 
	}
	cin >> t;
	while(t--){
		cin >> n;
		int res = d[n];
		for(int i = n-1; i >= 1; i--){
			res = (res + d[i] * 2 * dp[n-i-1] % mod) % mod;
		}
		cout << res << "\n";
	}
	return 0;
}