题意:
给你一个长度为50的数字串,问你有多少个子序列
构成的数字可以被3整除答案对1e9+7取模
输入:输入一个字符串,由数字构成,长度小于等
于50
输出:一个整数
题解:
这题挺难的,思路不好开,但是还是可以做,由
于字符串最长为50,所以字符串所有加起来的
和最大和不超过450,我们可以用01背包思想做。
定义dp[i][j],i代表字串长度,j代表和,dp[i]
[j]代表长度为i的字串中可以组成多少个j
核心代码解析:
for(int i=1; i<=len; i++)
{
for(int j=0; j<=450; j++)
{
dp[i][j]=dp[i-1][j];
if(di_n[i]==j)
{
dp[i][j]++;
}
if(j>=di_n[i])
{
dp[i][j]+=dp[i-1][j-di_n[i]];
dp[i][j]%=mod;
}
}
}
dp[i][j]=dp[i][j-1]代表当前i长度字串组成j个数为上一层的个数
然后对该层的进行操作,如果di_n[i]==j说明组成当前层组成j的加1
如果j>=di_n[i],dp[i][j]+=dp[i-1][j-di_n[i]],代表之前的+di_n[i]
可以组成j的个数
AC代码:
#include<bits/stdc++.h>
using namespace std;
//01背包思路解决线性dp
#define maxn 1005
#define mod 1000000000+7
int dp[maxn][maxn];//代表每个数的数量
int di_n[maxn],len;//存数
char s[maxn];
void init()
{
len=strlen(s+1);
for(int i=1; i<=len; i++)
{
di_n[i]=s[i]-'0';
}
}
void slove_dp()
{
init();
for(int i=1; i<=len; i++)
{
for(int j=0; j<=450; j++)
{
dp[i][j]=dp[i-1][j];//当前i,j大小的个数i-1,j大小的个数
if(di_n[i]==j)
{
dp[i][j]++;
}
if(j>=di_n[i])
{
dp[i][j]+=dp[i-1][j-di_n[i]];
dp[i][j]%=mod;
}
}
}
int ans=0;
for(int i=0; i<=450; i+=3)
{
ans+=dp[len][i];
ans%=mod;
}
printf("%d\n",ans);
}
int main()
{
scanf("%s",s+1);
slove_dp();
}