首页 > 其他分享 >被3整除的子序列

被3整除的子序列

时间:2023-03-16 23:12:05浏览次数:45  
标签:10 int 个数 序列 整除 mod

被3整除的子序列

image.png

思路

判断被\(3\)整除

当一个数的数位和为\(3\)的倍数时,该数就能被\(3\)整除。

证明

一个十进制数可以表示为\(a_1*10^{b_1}+a_2*10^{b_2}+...+a_n*10^{b_n}\)的形式。
通过,\((a*b) \,\ mod \,\ 3 = [(a \,\ mod \,\ 3) * (b \,\ mod \,\ 3)] \,\ mod \,\ 3\),再通过\(10 \,\ mod \,\ 3 = 1\),可以推出\(10^{x} \,\ mod \,\ 3 = 1\)。
因此,十进制数的每一个项都可以转化为以下形式:
\(a_i*10^{b_i} \,\ mod \,\ 3 = [(a_i \,\ mod \,\ 3) * (10^{b_i} \,\ mod \,\ 3)] \,\ mod \,\ 3 = [(a_i \,\ mod \,\ 3) *1] \,\ mod \,\ 3 = a_i \,\ mod \,\ 3\)
那么,\(a_1*10^{b_1}+a_2*10^{b_2}+...+a_n*10^{b_n} = (a_1 + a_2 + ... + a_n) \,\ mod \,\ 3\),就成立了。
当这个式子结果为\(0\)时,说明对应的十进制数就能被\(3\)整除。

动态规划

状态表示

\(f[i][j]\)在前\(i\)个数中选数,构成的子序列的数位和对\(3\)取模后为\(j\)的所有方案

状态计算

设第\(i\)个数为\(k\)。
(1)单独取第\(i\)个数,\(f[i][k\%3]\)方案数加一
(2)将第\(i\)个数拼接在前\(i-1\)个数中选出的子序列后面,构成的子序列数位和对\(3\)取模后为\(j\)。
相当于选择前\(i-1\)个数中选出的子序列,其数位和为\(p\),\((p+k) \%3=j\),则\(p = (j-k+3)\%3\),
对应\(f[i-1][p]\)。
(3)不选第\(i\)个数,子序列数位和对\(3\)取模为\(j\),对应\(f[i-1][j]\)。
因此,\(f[i][j] = f[i-1][j]+f[i-1][p]\),如果\(k\%3=j\),\(f[i][j]\)还需要加一。

最后的答案即为\(f[n][0]\),前\(n\)个数中选数,构成的子序列的数位和对\(3\)取模后为\(0\),即能被\(3\)整除。

代码实现

#include <bits/stdc++.h>
using namespace std;

const int N = 1e2;

const int mod = 1e9+7;

int f[N][3];
char str[N];

int main()
{
    cin>>str+1;
    int n = strlen(str+1);
    for(int i=1;i<=n;i++)
    {
        int k = (str[i]-'0')%3;
        f[i][k] = (f[i][k]+1)%mod;
        for(int j=0;j<3;j++)
        {
            f[i][j] = (f[i][j]+f[i-1][j])%mod;
            int p = (j-k+3)%3;
            f[i][j] = (f[i][j]+f[i-1][p])%mod;
        }
    }
    cout<<f[n][0];
    
    return 0;
}

标签:10,int,个数,序列,整除,mod
From: https://www.cnblogs.com/ycm-zs/p/17224586.html

相关文章