洛谷P7158题解
思路
总体上看下来,这道题不能用爆搜( \(1\le n\le 10^5\) ),所以说,可行的方法就是 dp。又注意到,以任何一个数字为 \(k\) 都是等价的,所以说这道题的答案与 \(k\) 无关,接下来的问题就是转移方程了。
转移方程
我们建立两个数组 \(dp1\) 和 \(dp2\) 我们用第一个数组存储在第 \(i\) 位上符合要求的数的个数,用第二个数组存储不符合要求的数目。而对于在 \(i+1\) 位上的所有数,我们可以理解为是在第 \(i\) 位的数后加入一个数字得到的,所以说 \(i+1\) 位上的符合要求的数必定是由第 \(i\) 位的符合要求的数与一个不为 \(k\) 的数字组成的所有数和在第 \(i\) 位上符合要求的数与 \(k\) 组成的,同理也可以得到 \(dp2\) 的转移方程。
\[\mathit{dp1}_{i}=\mathit{dp1}_{i-1}\times 9+\mathit{dp2}_{i-1}
\]
\[\mathit{dp2}_{i}=\mathit{dp2}_{i-1}\times 9+\mathit{dp1}_{i-1}
\]
同时在 \(n=1\) 时要注意特判,直接输出 \(9\)。
接下来就是代码实现的过程了。(记得不要忘了取模)
Code
#include <stdio.h>
using namespace std;
int main(){
int t;
scanf("%d",&t);
long long dp1[114519],dp2[114519];//数组必须要开的比n的最大值大
dp1[1]=8,dp2[1]=1;
for(int i=1;i<=114514;i++){//循环次数只要超过10的五次方即可
dp1[i]+=dp2[i-1];
dp1[i]+=dp1[i-1]*9;
dp1[i]%=998244353;
dp2[i]+=dp2[i-1]*9;
dp2[i]+=dp1[i-1];
dp2[i]%=998244353;
}
for(int i=1;i<=t;i++){
int n,k;
scanf("%d%d",&n,&k);
if(n==1){
printf("9\n");
continue;
}//特判
printf("%d\n",dp1[n]);
}
return 0;
}

浙公网安备 33010602011771号