题目
分析
根据题目可以发现,一个数
(
1
≤
n
≤
1
0
5
)
(1\leq n\leq 10^5)
(1≤n≤105)的数字根其实就是这个数按
9
9
9取模的值
(
一
个
数
取
模
结
果
为
0
说
明
这
个
数
的
数
字
根
是
9
)
(一个数取模结果为0说明这个数的数字根是9)
(一个数取模结果为0说明这个数的数字根是9).
题目问的是几个数之和的数字根,按照模运算的性质:
(
a
+
b
)
%
p
=
(
a
%
p
+
b
%
p
)
%
p
(a+b)\%p=(a\%p+b\%p)\%p
(a+b)%p=(a%p+b%p)%p
依然是几个数的数字根之和的取模结果,所以我们在一开始就可以对数据全部进行取模操作。
确定思路,题目问的是组合数,在每一种组合中,其实对于个体来说只有两种情况,那么这道问题跟之前写的砝码称重有点像,都是01背包的问题。
步骤一:确定状态
步骤二:确定状态转移方程
步骤三:确定边界情况和初始条件
步骤四:确定计算顺序
步骤一:确定状态
以
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示在处理完第
i
i
i个人后第
j
j
j种情况的对应组合种数。
步骤二:确定状态转移方程
已知在处理完第
i
−
1
i-1
i−1个人后所有情况的对应组合种数,那么想要求
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]
d
p
[
i
]
[
j
]
=
(
d
p
[
i
−
1
]
[
j
]
+
d
p
[
i
−
1
]
[
(
j
+
9
−
a
[
i
]
)
%
9
]
)
%
m
o
d
dp[i][j]=(dp[i-1][j]+dp[i-1][(j+9-a[i])\%9])\%mod
dp[i][j]=(dp[i−1][j]+dp[i−1][(j+9−a[i])%9])%mod
d
p
[
i
−
1
]
[
j
]
dp[i-1][j]
dp[i−1][j]表示第
i
i
i个人不参加组合,继承
i
−
1
i-1
i−1个人的条件下情况
j
j
j对应的组合种数;
d
p
[
i
−
1
]
[
(
j
+
9
−
a
[
i
]
)
%
9
]
dp[i-1][(j+9-a[i])\%9]
dp[i−1][(j+9−a[i])%9]表示第
i
i
i个人参加组合后,由情况
j
−
a
[
i
]
j-a[i]
j−a[i]变为情况
j
j
j,要考虑取模。
步骤三:确定边界情况和初始条件
d
p
[
0
]
[
0
]
=
1
dp[0][0]=1
dp[0][0]=1
步骤四:确定计算顺序
自上往下。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fir(i,a,b) for (int i = (a); i <= (b); i++)
const ll N=1e5+9;
const ll mod = 998244353;
ll dp[N][9];
ll a[N];
ll n;
int main(){
cin>>n;
dp[0][0]=1;
fir(i,1,n){
cin>>a[i];
a[i]%=9;
fir(j,0,8){
dp[i][j]=(dp[i-1][j]+dp[i-1][(j+9-a[i])%9])%mod;
}
}
fir(i,1,8)
cout<<dp[n][i]<<" ";
cout<<dp[n][0]-1;
}