做题记录 2021.10.20 被3整除的子序列

给你一个长度不大于50的数字串,问你有多少个子序列构成的数字可以被3整除
答案对1e9+7取模

思路:由小学数学知识可以看出是DP,但如果直接定义dp数组表示能整除的个数,状态转移就很困难。因此定义dp[i][j]=前i个数中对3的模为j的个数。只要输出dp[n][0] (n为字符串的长度)即可。
dp[i][j]可分为两种情况:
1.不将第i个数加进序列;
2.将第i个数加进序列;
因此可以得到dp[i][j]=dp[i-1][j]+dp[i-1][?]

其中?处我想了很久,最终还是没想出来一个通用的式子,就打了个表
need[3][3]={{0,2,1},{1,0,2},{2,1,0}}; //need[i][j]表示要求余数为i,末尾余数为j需要的上一次的余数
因此dp[i][j]=dp[i-1][j]+dp[i-1][need[j][s[i]%3]]。
但这里有一个要注意的地方:一个数单独也可以成一个序列,换句话说,dp[i][s[i]%3]需要额外+1,之前这个地方一直没想通卡了好久。

看了题解才知道第二维可以写成(j+3-(s[i]%3))%3

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MOD 1000000007
#define long long long
const int M=52;
using namespace std;
char s[M];
long dp[M][3];

int main() {
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0; i<len; i++) {
    	int tmp=(s[i]-'0')%3;
    	for(int j=0; j<3; j++) {
    		dp[i+1][j]=dp[i][j]+dp[i][(3+j-tmp)%3];
		}
		dp[i+1][tmp]++;
	}
	printf("%d",dp[len][0]%MOD);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值