信奥赛CSP-J复赛集训(DP专题)(14):P7158 「dWoi R1」Password of Shady
信奥赛CSP-J复赛集训(DP专题)(14):P7158 「dWoi R1」Password of Shady
题目背景
天海兰太郎被杀后,最原看到图书架后面刷卡器里的尘土并没有消散,陷入了沉思 ……
最原在想,黑幕是如何做到刷卡器的尘土没有消散但是还成功进入了黑幕的房间呢?然后他再次确认了刷卡器,发现了一个密码盘,密码盘下写着一行文字「真正的秘密总是被谎言欺骗,但黑幕不至于欺骗自己」,然后还有一道题,于是最原要用 1min 的时间解出这道题。
题目描述
这道题要求最原构造一个 n n n 位数,并且满足以下两个要求:
- 「强者从不说废话」,代表着这个数没有前导零, 0 0 0 没有前导零且是一位数。
- 「强者善于成 k k k 对合作」,代表着这个数的所有数位中有偶数个 k k k, 0 0 0 是偶数。
最原很快就让入间制作了一个造数器,但是造数器还需要输入有多少个满足要求的数,于是他就求助于了你,因为做造数器已经用了 59.5s,所以他想让你 0.5s 求出有多少个符合要求的数。
答案对 998 244 353 998\ 244\ 353 998 244 353 取模。
输入格式
本题多测,测试组数为
t
t
t。
对于每组数据,一行两个整数
n
,
k
n,k
n,k。
输出格式
对于每组数据,一行一个整数代表答案。
输入输出样例 #1
输入 #1
2
2 3
11 4
输出 #1
73
842367440
说明/提示
样例 1 解释
第一组数据,满足要求的数为:
- 0 0 0 个 3 3 3, 10 ∼ 12 10\sim 12 10∼12, 14 ∼ 22 14 \sim 22 14∼22, 24 ∼ 29 24 \sim 29 24∼29, 40 ∼ 42 40 \sim 42 40∼42, 44 ∼ 52 44 \sim 52 44∼52, 54 ∼ 62 54 \sim 62 54∼62, 64 ∼ 72 64 \sim 72 64∼72, 74 ∼ 82 74 \sim 82 74∼82, 84 ∼ 92 84 \sim 92 84∼92, 94 ∼ 99 94\sim 99 94∼99。
- 2 2 2 个 3 3 3, 33 33 33。
第二组数据的样例解释写了 114514 行,但赛前 0.1s 不小心被黑白熊偷走了,书虫来不及补了。
数据规模与约定
本题采用捆绑测试。
- Subtask 1(5 pts): n = 1 n=1 n=1。
- Subtask 2(25 pts): n ≤ 6 n \le 6 n≤6。
- Subtask 3(25 pts): t ≤ 100 t \le 100 t≤100。
- Subtask 4(45 pts):无特殊限制。
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1≤n≤105, 1 ≤ k ≤ 9 1 \le k \le 9 1≤k≤9, 1 ≤ t ≤ 1 0 6 1 \le t \le 10^6 1≤t≤106。
AC代码(100分)
#include<bits/stdc++.h>
using namespace std;
/*dp思路
1、同时记录更新两个状态
dp1[i] :构造满足要求的i位数
dp2[i] :构造不满足要求的i位数
2、 一个满足要求的 i 位数,可以由一个满足要求的 i-1 位数加上一位除了 k 之外的数位得来
或者以由一个不满足要求的 i-1 位数加上一位 k
一个不满足要求的 i 位数,可以由一个不满足要求的 i-1位数加上一位除了 k 之外的数得来
或者由一个满足要求的 i-1位数加上一位k
3、状态转移方程为:
dp1[i] = dp1[i-1]*9 + dp2[i-1]
dp2[i] = dp2[i-1]*9 + dp1[i-1]
*/
const int N=1e5+10;
int t,n,k;
long long dp1[N],dp2[N];//注意开long long
int main(){
//用dp递推出1~10^5的所有答案
dp1[1]=8;//1位数比较特殊,初始时不考虑0
dp2[1]=1;
for(int i=2;i<=100000;i++){
dp1[i] = (dp1[i-1]*9 + dp2[i-1])%998244353;
dp2[i] = (dp2[i-1]*9 + dp1[i-1])%998244353;
}
//输出答案
cin>>t;
while(t--){
scanf("%d%d",&n,&k);//t范围较大,不用cin
if(n==1) printf("9\n"); //特判1位数
else printf("%lld\n",dp1[n]); //t范围较大,不用cout
}
return 0;
}
文末彩蛋:
关注并查看老师的个人主页,学习完整csp信奥赛完整系列课程: https://edu.csdn.net/lecturer/7901