Bootstrap

被3整除的子序列【区间DP】

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目链接:https://ac.nowcoder.com/acm/problem/21302
题目描述:
给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除
答案对1e9+7取模
输入描述:
输入一个字符串,由数字构成,长度小于等于50
输出描述:
输出一个整数
示例1
输入
132
输出
3
示例2
输入
9
输出
1
示例3
输入
333
输出
7
示例4
输入
123456
输出
23
示例5
输入
00
输出
3
备注:
n为长度
子任务1: n <= 5
子任务2: n <= 20
子任务3: 无限制
AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod=1e9+7;
char a[55];//用来存放字符串
int b[55];//用来存放每一位字符转换后的数字0、1、2
ll dp[55][55][5];
int main()
{
    cin>>a;
    memset(dp,0,sizeof(dp));
    int n=strlen(a);
    for(int i=0;i<n;i++)
    {
          b[i]=(a[i]-'0')%3;
          dp[i][i][b[i]]=1;//自身设为1,dp[i][j][k]表示区间i到j内被3除余k的可能数
    }
    for(int i=n-1;i>=0;i--)
    {
          for(int j=i;j<n-1;j++)
          {
               if((b[j+1])==0)//无影响
               {
                    dp[i][j+1][0]=2*dp[i][j][0]+1;
                    dp[i][j+1][1]=2*dp[i][j][1];
                    dp[i][j+1][2]=2*dp[i][j][2];
               }
               else if(b[j+1]==1)
               {
                    dp[i][j+1][0]=dp[i][j][0]+dp[i][j][2];//dp[i][j+1][0]由原先dp[i][j][0]和dp[i][j][2]影响,因为(1+2)%3==0。下同
                    dp[i][j+1][1]=dp[i][j][1]+dp[i][j][0]+1;
                    dp[i][j+1][2]=dp[i][j][2]+dp[i][j][1];
               }
               else if(b[j+1]==2)
               {
                    dp[i][j+1][0]=dp[i][j][0]+dp[i][j][1];
                    dp[i][j+1][1]=dp[i][j][1]+dp[i][j][2];
                    dp[i][j+1][2]=dp[i][j][2]+dp[i][j][0]+1;
               }
               for(int k=0;k<3;k++)
               {
                    dp[i][j+1][k]%=mod;
               }
          }
    }
    printf("%lld\n",dp[0][n-1][0]);
    return 0;
}

我一定可以的!!!

;