C 只有300分的动归
之我不会
C - 1111gal password Editorial
/
Time Limit: 2 sec / Memory Limit: 1024 MB
Score : 300300 points
Problem Statement
Given an integer NN, find the number of integers XX that satisfy all of the following conditions, modulo 998244353998244353.
- XX is an NN-digit positive integer.
- Let X_1,X_2,\dots,X_NX1,X2,…,XN be the digits of XX from top to bottom. They satisfy all of the following:
- 1 \le X_i \le 91≤Xi≤9 for all integers 1 \le i \le N1≤i≤N;
- |X_i-X_{i+1}| \le 1∣Xi−Xi+1∣≤1 for all integers 1 \le i \le N-11≤i≤N−1.
Constraints
- NN is an integer.
- 2 \le N \le 10^62≤N≤106
Input
Input is given from Standard Input in the following format:
NN
Output
Print the answer as an integer.
Sample Input 1 Copy
Copy
4
Sample Output 1 Copy
Copy
203
Some of the 44-digit integers satisfying the conditions are 1111,1234,7878,65451111,1234,7878,6545.
Sample Input 2 Copy
Copy
2
Sample Output 2 Copy
Copy
25
Sample Input 3 Copy
Copy
1000000
Sample Output 3 Copy
Copy
248860093
Be sure to find the count modulo 998244353998244353.
官方解释
Method 1: Design DP by writing down the recurrence relations
For example, we consider the first Sample. How many four-digit flat numbers are there?
Let’s divide them by cases to count them.
There are many ways of case division; one natural way is to divide them depending on the first digit.
For instance, what if the first digit is 77?
7???7???
In this case, we want to find how many ways are there to fill the last three digits to make the entire integer a flat number. Let’s denote the answer by f(7???)f(7???).
It’s still difficult to find. So let’s divide them by cases again.
A natural idea is to consider the second digit. By the condition, the second digit should be either 66, 77, or 88.
76??76??
77??77??
78??78??
That is, f(7???) = f(76??) + f(77??) + f(78??)f(7???)=f(76??)+f(77??)+f(78??).
Here, the number of ways to fill ??’s in 76??76?? so that it results in a flat number is equal to the number of ways to fill ??’s in 6??6?? so that it results in a flat number. (The leading 77 in 76??76?? does not affect to ??’s to be filled.) So we have
f(76??) = f(6??)f(76??)=f(6??).
Together with the observation above, we obtain a simple recurrence relation of ff:
f(7???) = f(6??) + f(7??) + f(8??)f(7???)=f(6??)+f(7??)+f(8??).
We will now apply this recurrence relation repeatedly. For example, when we want the value of f(6??)f(6??) to obtain the right hand side of the equation above, we can use the following equation:
f(6??) = f(5?) + f(6?) + f(7?)f(6??)=f(5?)+f(6?)+f(7?)
which can be obtained by the similar way as before. Note that, when repeating in this way, the argument of ff is always a single-digit integer followed by ??’s.
Now, let’s find the values of ff for all the arguments of that form.
Prepare a two-dimensional array dp[][]dp[][]. The value of dp[n][k]dp[n][k] is the value of f(k??? \dots???)f(k???…???) (where the argument is a string consisting of kk followed by n-1n−1 copies of ??). For example, dp[4][7] = f(7???)dp[4][7]=f(7???). By the recurrence relation we obtained before, we have dp[4][7] = dp[3][6] + dp[3][7] + dp[3][8]dp[4][7]=dp[3][6]+dp[3][7]+dp[3][8].
How to fill the array with correct values?
For example, in order to find dp[4][7]dp[4][7], we should already know the correct values of dp[3][6], dp[3][7]dp[3][6],dp[3][7], and dp[3][8]dp[3][8].
In this case, it is sufficient to fill them in the increasing order of n. (Note that we should be careful enough of the order of filling the array.)
Specifically, we can implement as follows.
- For n = 1, 1 \le k \le 9n=1,1≤k≤9, let dp[n][k] = 1dp[n][k]=1.
- Next, iterate nn for 22 and greater in the increasing order to fill dp[n][k]dp[n][k].
- For example, let dp[4][7] = dp[3][6] + dp[3][7] + dp[3][8]dp[4][7]=dp[3][6]+dp[3][7]+dp[3][8].
Note when implementing the special case for k = 1k=1 and k = 9k=9. For more details, please refer to the sample code at the bottom of the editorial.
代码
#include<bits/stdc++.h>
#define mod 998244353
using namespace std;
int dp[1048576][10]={0};
int main(){
int n;
cin >> n;
for(int i=1;i<=9;i++){dp[1][i]=1;}
for(int d=2;d<=n;d++){
for(int i=1;i<=9;i++){
for(int j=max(1,i-1);j<=min(9,i+1);j++){
dp[d][i]+=dp[d-1][j];
dp[d][i]%=mod;
}
}
}
int res=0;
for(int i=1;i<=9;i++){
res+=dp[n][i];
res%=mod;
}
cout << res << '\n';
return 0;
}
官方代码,我觉得它改了一下,让我觉得很迷,我感觉我的更清楚蛤,有没有区间dp的味道
#include<bits/stdc++.h>
#define mod 998244353
using namespace std;
int dp[1048576][10]={0};
int main(){
int n;
cin >> n;
for(int i=1;i<=9;i++){dp[1][i]=1;}
for(int d=2;d<=n;d++){
for(int i=1;i<=9;i++){
for(int j=max(1,i-1);j<=min(9,i+1);j++){
dp[d][j]+=dp[d-1][i];
dp[d][j]%=mod;
}
}
}
int res=0;
for(int i=1;i<=9;i++){
res+=dp[n][i];
res%=mod;
}
cout << res << '\n';
return 0;
}