AtCoder Beginner Contest 242

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值