被3整除的子序列
网址为:被3整除的子序列 (nowcoder.com)
题目描述
给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除
答案对1e9+7取模
输入描述:
输入一个字符串,由数字构成,长度小于等于50
输出描述:
输出一个整数
示例1
输入
复制132
132
输出
复制3
3
示例2
输入
复制9
9
输出
复制1
1
示例3
输入
复制333
333
输出
复制7
7
示例4
输入
复制123456
123456
输出
复制23
23
示例5
输入
复制00
00
输出
复制3
3
备注:
n为长度 子任务1: n <= 5 子任务2: n <= 20 子任务3: 无限制
动态规划问题,可将其分成子状态:第n位的数字mod3等于0,1,2时。可以表示为dp[i][0],dp[i][1],dp[i][2],i表示为第i位。
则可以推出:
1.n%3 == 0时,i位等于前i-1位mod3 ==0的子序列个数加上当前i位后多出来的子序列个数加上n本身也是一个mod3 ==0的子序列,表达式如下:
dp[i][0] = dp[i - 1][0] + dp[i - 1][0] + 1
dp[i][1] = dp[i -1][1] + dp[i - 1][1]
dp[i][2] = dp[i - 1][2] + dp[i -1][2]
2.n%3 == 1时,前i-1位mod3==2的子序列后面添加一位mod3 ==1的数就可以整除3,比如2mod3=2,21mod3=0
dp[i][0]=dp[i - 1][0] + dp[i -1][2]
dp[i][1]=dp[i - 1][1] + dp[i - 1][0] + 1//加一是因为它本身也是一种情况
dp[i][2]=dp[i - 1][2] + dp[i -1][1]
3.n%3==2时,
dp[i][0] = dp[i - 1][0] + dp[i - 1][1]
dp[i][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;
#define int long long
#define endl '\\n'
#define YES cout<<"YES"<<endl
#define NO cout<<"NO"<<endl
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
const int N = 1e5+10;
int dp[55][5];
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
void solve()
{string s;cin>>s;int len=s.size();s=" "+s;for(int i=1;i<=len;i++){if((s[i]-'0')%3==0){dp[i][0]=(2*dp[i-1][0]+1)%mod;dp[i][1]=(2*dp[i-1][1])%mod;dp[i][2]=(2*dp[i-1][2])%mod;}else if((s[i]-'0')%3==2){dp[i][0]=(dp[i-1][0]+dp[i-1][1])%mod;dp[i][1]=(dp[i-1][1]+dp[i-1][2])%mod;dp[i][2]=(dp[i-1][0]+dp[i-1][2]+1)%mod;}else if((s[i]-'0')%3==1){dp[i][0]=(dp[i-1][0]+dp[i-1][2])%mod;dp[i][1]=(dp[i-1][1]+dp[i-1][0]+1)%mod;dp[i][2]=(dp[i-1][2]+dp[i-1][1])%mod;}}cout<<dp[len][0]<<endl;
}
signed main()
{int t;t=1;while(t--){solve();}
}
仔细观察发现dp[i][]只与dp[i - 1][]有关系,那么我们可以考虑用变量记录前一位的三个状态,从而降低空间复杂度,从二维变成一维
#include<bits/stdc++.h>
using namespace std;const int mod = 1e9+7;int main(){string str;cin >> str;int len = str.size();int num[len + 5];for(int i = 1;i <= len; ++i){num[i] = str[i - 1] - '0';} int dp[5]={0},one = 0,two = 0,zero = 0;for(int i = 1;i <= len; ++i){if(num[i] % 3 == 0){dp[0]=(2 * zero + 1) % mod;dp[1]=(2 * one) % mod;dp[2]=(2 * two) % mod; }else if(num[i] % 3 == 1){dp[0]=(zero + two) % mod;dp[1]=(one + zero + 1) % mod;dp[2]=(two + one) % mod;}else if(num[i] % 3 == 2){dp[0] = (zero + one) % mod;dp[1] = (one + two) % mod;dp[2] = (two + zero + 1) % mod;}zero = dp[0];one = dp[1];two = dp[2];}cout << dp[0] << '\\n';return 0;
}