题目链接
题目大意
给你一个长度为 50 的数字串,问你有多少个子序列构成的数字可以被 3 整除
答案对
1
e
9
+
7
1e^9+7
1e9+7取模
输入描述
输入一个字符串,由数字构成,长度小于等于50
输出描述
输出一个整数
输入样例
132
输出样例
3
动态规划线性dp
1.确定状态
f
[
i
]
[
j
]
f[i][j]
f[i][j]:以
s
[
i
]
s[i]
s[i] 结尾的数余数是
j
j
j,属性表示方案数。
2.状态转移
f
[
i
+
1
]
[
j
]
=
f
[
i
+
1
]
[
j
]
+
f
[
i
]
[
j
]
f[i+1][j] = f[i+1][j] + f[i][j]
f[i+1][j]=f[i+1][j]+f[i][j]
举个粟子,以样例为例。首先132的子序列有 1、3、13、2、12、32、132,有个结论就是一个数能被某个数整除,那么所有位置上的数字之和能被这个数整除,以 2 结尾的数据有 2、12、32、132 。12 可以看作
f
[
"
12
"
]
[
m
o
d
]
=
f
[
"
12
"
]
[
(
m
o
d
+
"
2
"
)
%
m
o
d
]
+
f
[
"
1
"
]
[
m
o
d
]
f["12"][mod] = f["12"][(mod+"2")\%mod] + f["1"][mod]
f["12"][mod]=f["12"][(mod+"2")%mod]+f["1"][mod]依次类推。
3.编码实现方式
1 dp[1][1] = 1;
03 dp[2][0] = 1;
002 dp[3][2] = 1;
1 ⇒ 12
13 ⇒ 132 ⇒ dp[3][(j+2)%3] = (dp[2][j] + dp[3][(j+2)%3])
2
3 ⇒ 32
for(int i = 1; i <= len; i++)
for(int j = 0; j < 3; j++)
for(int k = i+1; k <= len; k++)
f[k][(s[k]+j-'0')%3] =(f[k][(s[k]+j-'0')%3]+ f[i][j])%mod;
#include <cstdio>
#include <cstring>;
using namespace std;
const int mod = 1e9 + 7;
char s[55];
int f[55][3];
int main()
{
scanf("%s",s+1);
int len = strlen(s+1);
for(int i = 1; i <= len; i++) f[i][(s[i]-'0')%3] = 1;
for(int i = 1; i <= len; i++)
for(int j = 0; j < 3; j++)
for(int k = i+1; k <= len; k++)
f[k][(s[k]+j-'0')%3] =(f[k][(s[k]+j-'0')%3]+ f[i][j])%mod;
int ans = 0;
for(int i = 1; i <= len; i++) ans = (ans + f[i][0])%mod;
printf("%d\n",ans);
return 0;
}