被3整除的子序列(纯C语言)-动态规划

Posted 勇敢*牛牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了被3整除的子序列(纯C语言)-动态规划相关的知识,希望对你有一定的参考价值。

被3整除的子序列

题目描述

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

输入描述:

输入一个字符串,由数字构成,长度小于等于50

输出描述:

输出一个整数

示例1
输入

132

输出

3

示例2
输入

9

输出

1

示例3
输入

333

输出

7

备注:

n为长度
子任务1: n <= 5
子任务2: n <= 20
子任务3: 无限制

做题思路

简单说下题意,给定一个数字串,问有多少的子串可以被3整除。首先一个数如果可以被3整除,那么这个数各位和一定可以被3整除。所以这个题应该是线性dp,我们定义dp[i][j]为前i个中整除3余数为j(只有0,1,2三个数)的个数,然后从头到尾线性dp一遍就可以了。

首先题目中的子序列并不是连续的子序列,中间是可以有跳跃的。

例如字符串“134”
它的子串就有1,3,4,13,14(这个子串就是不连续的,中间跳过了一个3),134

然后我们设an为长度是n的字符串的子串数量,为了方便理解,下面我举几个例子;

例:
字符串“3”,长度n=1,a1=1;
字符串“32”,长度n=2,a2=3;
字符串“321”,长度你=3,a3=7;

可以看出an=an-1*2+1;
原理就是“32”的子串有3,2,32;
在增加了一位变成”321“后,子串变成了
3,2,32,31,21,321,1

不知道大家注意到没有,加粗的字体其实就是在前一个子串集合里的元素后面加上后加入的字符“1”,斜体的字体就是最后加上个新增加的字符“1”;

上面的例子主要是为了让大家能更好的理解长度为n的字符串与长度为n+1的字符串之间子串的关系,
其实长度为n+1的字符串它的子串就是包括了长度为n的字符串的子串,并在n的每个子串后面加上一个多出来的字符,再加上多出来的字符本身,那么子串对3求余的关系就如下面的例子
例:

字符串“123”,
子串1,2,3,12,13,23,123
对3求余为0的子串:3,12,123;(数量为3)
对3求余为1的子串:1,13;(数量为2)
对3求余为2的子串:2,23;(数量为2)

然后在字符串“123”的基础上加一个字符,这个要根据这个字符对3求余的不同情况进行分别讨论,
例1:

1234“(加入了新字符“4”,整个对3求余余1)
对3求余为0的子串:3,12,123,24,234;
数量为3+2
(这个2是上面对3求余为2的子串加上新字符“4”后形成的新子串,因为之前的子串余2,加上新字符对3求余余1,余下的2+1等于3,刚好又对3求余时余0,下面的子串也同理))
对3求余为1的子串:1,13,34,124,1234,4
(数量为2+3+1(3的来源可以参考上面2的来源,这里就不细讲了,1的来源就是新加入的字符“4”))
对3求余为2的子串:2,23,14,134(数量为2+2)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void fun(char num[])//行数,列数 
	int N = 1e9 + 7;
 	int lenth = strlen(num), m = 0,i;
	long long date[50][3] =  0 ;
	//	初始 m 
    m = (num[0] - '0') % 3;
    date[0][m] = 1;
    
    for (i = 1;i < lenth;i++)
        m = (num[i] - '0') % 3;
        switch (m)
	        //新字符余0的情况
	        case 0:
	            date[i][0] = (date[i - 1][0] * 2 + 1) % N;
	            date[i][1] = (date[i - 1][1] * 2) % N;
	            date[i][2] = (date[i - 1][2] * 2) % N;
	            break;
	        
	        //新字符余1的情况
	        case 1:
	            date[i][0] = (date[i - 1][0] + date[i - 1][2]) % N;
	            date[i][1] = (date[i - 1][1] + date[i - 1][0] + 1) % N;
	            date[i][2] = (date[i - 1][2] + date[i - 1][1]) % N;
	            break;
	        
	        //新字符余2的情况
	        case 2:
	            date[i][0] = (date[i - 1][0] + date[i - 1][1]) % N;
	            date[i][1] = (date[i - 1][1] + date[i - 1][2]) % N;
	            date[i][2] = (date[i - 1][2] + date[i - 1][0] + 1) % N;
	            break;
	        
        
    
    printf("%d",date[lenth - 1][0] % N) ;//输出时取余,按照题目要求
 
int main() 
	char num[50];
	scanf("%s",num);
	fun(num);
	return 0;

以上是关于被3整除的子序列(纯C语言)-动态规划的主要内容,如果未能解决你的问题,请参考以下文章

动态规划不同的子序列

判断整除(动态规划,递推)

动态规划---最长公共子序列

被3整除的子序列

C语言程序,输入N个点的坐标,判断能否构成凸多边形

动态规划——最大连续子序列和