链接:https://ac.nowcoder.com/acm/problem/21302
来源:牛客网
给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除
答案对1e9+7取模
输入描述:
输入一个字符串,由数字构成,长度小于等于50
输出描述:
输出一个整数
思路:这道题的转移很有意思,设dp[i][k] 表示长度为 i 的数字串中模 3 等于 k 的子序列个数,其中(0<=k<=2)。
通过分析可以发现:
当第 i 个数模3等于0时:dp[i][0] = 2*dp[i-1][0]+1; dp[i][1] = 2*dp[i-1][1]; dp[i][2] = 2*dp[i-1][2];
当第 i 个数模3等于1时:dp[i][0] = dp[i-1][0]+dp[i-1][2]; dp[i-1][1] = dp[i-1][1]+dp[i-1][0]+1; dp[i][2] = dp[i-1][2]+dp[i-1][1];
当第 i 个数模3等于2时:dp[i][0] = dp[i-1][0]+dp[i-1][1]; dp[i-1][1] = dp[i-1][1]+dp[i-1][2]; dp[i][2] = dp[i-1][2]+dp[i-1][0]+1;
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e6+10;
const int modd = 1e9+7;
typedef long long ll;
const int inf = 0x3f3f3f3f;
string s;
int dp[100][5];
int a[100];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>s;
int len = s.length();
for(int i = 1;i <= len;i++){
a[i] = s[i-1]-'0';
if(a[i]%3 == 0){
dp[i][0] = (2*dp[i-1][0]+1)%modd;
dp[i][1] = (2*dp[i-1][1])%modd;
dp[i][2] = (2*dp[i-1][2])%modd;
}
else if(a[i]%3 == 1){
dp[i][0] = (dp[i-1][0]+dp[i-1][2])%modd;
dp[i][1] = (dp[i-1][1]+dp[i-1][0]+1)%modd;
dp[i][2] = (dp[i-1][2]+dp[i-1][1])%modd;
}
else if(a[i]%3 == 2){
dp[i][0] = (dp[i-1][0]+dp[i-1][1])%modd;
dp[i][1] = (dp[i-1][1]+dp[i-1][2])%modd;
dp[i][2] = (dp[i-1][2]+dp[i-1][0]+1)%modd;
}
}
cout<<dp[len][0]<<endl;
return 0;
}
本文介绍了一种使用动态规划(DP)解决特定数学问题的方法:计算一个长度不超过50的数字串中,能被3整除的子序列数量。文章详细解析了DP状态转移方程,分享了一段C++实现代码,该代码利用三维DP数组记录模3余数为0、1、2的子序列个数,最终输出模1e9+7后的结果。

被折叠的 条评论
为什么被折叠?



