牛客ACM-被3整除的子序列
作者:互联网
题目描述
给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除答案对1e9+7取模
输入描述:
输入一个字符串,由数字构成,长度小于等于50
输出描述:
输出一个整数示例1
输入
132
输出
3示例2
输入
9
输出
1示例3
输入
333
输出
7
这个是属于动态规划类型的题目,首先就会想到把大的问题分解为小问题来解决,把数字串从第一位逐步向最后一位进行求解任务,
1-为了方便处理,可以再每次循环的时候把数字串都进行模3处理 m = (s[i]-'0')%3; m暂时存放这一位的模3余数
2-需要确定状态转移方程,用dp[i][j]来表示在数字串的长度为i时,此时数字串模3余数为j的个数,
当前位数的模3余数有三种情况(m=0或1或2):
此时dp[i][j]应该为长度为i-1时的dp[i-1][j]加上dp[i-1][(j-m+3)%3]
加入当前位的模3余数为1:我们在求dp[i][0]时肯定是加上dp[i-1][0]然后还要加上dp[i-1][?](前i-1长度的子序列模3余数为2的个数),此时的(?+m)%3=0
也就是说?应该为2 我们的状态转移此时就是找到求?的规律:?=(j-m+3)%3;
下面是我列出的列子:从中我们可以退出状态转移方程为:dp[i][j] = dp[i-1][j]+dp[i-1][(j-m+3)%3];
(1)m=0:dp [i][1]=dp[i-1][1]+dp[i-1][2] dp[i][2]=dp[i-1][2]+dp[i-1][0] 最后加上第i位的模3情况: 代码:
dp[i][0]=dp[i-1][0]+dp[i-1][0]
dp[i][1]=dp[i-1][1]+dp[i-1][1]
dp[i][2]=dp[i-1][2]+dp[i-1][2]
(2)m=1:
dp[i][0]=dp[i-1][0]+dp[i-1][2]
dp[i][1]=dp[i-1][1]+dp[i-1][0]
dp[i][1]=dp[i-1][1]+dp[i-1][0]
(3)m=2:
dp[i][0]=dp[i-1][0]+dp[i-1][1]
#include<bits/stdc++.h> using namespace std; const int mod = 1e9+7; int main(){ int dp[55][3]; int m=0; string str; cin>>str; //获取长度 int strLength = str.length(); memset( dp, 0, sizeof(dp)) ;//初始化数组 dp[0][(str[0]-'0')%3] = 1; for(int i=1; i < strLength; i++){ m = (str[i]-'0')%3; for(int j=0; j<3; j++){ dp[i][j] = (dp[i-1][j] + dp[i-1][(j-m+3)%3])%mod; } dp[i][m] = (dp[i][m] + 1)%mod;//最后加上第i位的模3情况: } cout<<dp[strLength-1][0]<<endl; }
标签:数字串,int,ACM,牛客,str,长度,余数,整除,dp 来源: https://www.cnblogs.com/Tisou1/p/12224095.html