牛客周赛 Round 1

D 游游的9的倍数

题目描述

游游拿到了一个数字串,她想取一个该数字串的子序列(子序列在原串中可以不连续),使得该子序列是9的倍数。子序列可以包含前导零。
游游想知道,一共能取多少个合法的子序列?答案请对 \(10^9+7\) 取模。
我们定义,若两个子序列在原串中的位置不同,则认为它们不同。

输入描述

一个长度不超过200000的,仅由'0'~'9' 十种字符组成的字符串。

输出描述

子序列是9的倍数的数量。答案请对 \(10^9+7\) 取模。

解题思路

由于是子序列,所以对于每个位置有选和不选两种选择,可以考虑用动态规划来解决。

根据9的倍数按所有位数求和仍是9的倍数这一数学性质,可以创建一个二维数组,第一维记录当前是第几个数字,第二位记录选或不选这个数字对9取模后的值,因此我们可以得到以下两个转移方程:
不选

dp[i+1][j]=dp[i][j];

int l=(j+s[i]-'0')%9;
dp[i+1][l]+=dp[i][j]; 
dp[i+1][l]%=MOD;

对每一位进行以上操作后 \(dp[n][0]-1\) 即是答案。

代码实现

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
const int MOD=1e9+7;
int dp[N][10];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    string s;
    cin>>s;
    int n=s.size();
    dp[0][0]=1;
    for(int i=0;i<n;i++){
        //不选这个数字
        for(int j=0;j<9;j++){
            dp[i+1][j]=dp[i][j];
        }
        //选这个数字
        for(int j=0;j<9;j++){
            int l=(j+s[i]-'0')%9;
            dp[i+1][l]+=dp[i][j]; 
            dp[i+1][l]%=MOD;
        }
    }
    cout<<dp[n][0]-1<<"\n";
}
posted @ 2024-06-02 23:56  udiandianis  阅读(66)  评论(0)    收藏  举报