参考牛客官方题解视频思路(https://www.bilibili.com/video/BV1fHBjYjEqq)
题意
给定一个01串,但其中有一些被'?'字符代替。 希望将'?'替换成'0'或者'1'字符,使得该串表示的正整数是13的倍数。求出有多少种方案(需要对1e9+7取模)
思路
首先需要观察到 13 这个常数较小 。
题目中 使得表示的正整数是 13 的倍数,即为该正整数 %13 为 0
根据取模运算的规律(??),我们得到
(x*10)%13 == (x%13)*10%13
(x*10+1)%13 == ((x%13)*10+1)%13
也就是说,只需要得到前 i 位数的余数,和当前位的个位数,就可以求得余数结果。而不需要知道前 i 位数具体是什么。换句话说,前 i 位余数相同的情况可以一并处理。这为我们使用动态规划快速求得答案提供基础。
所以可以得到以下的转移规律:
//dp[i][j] 代表前 i 位数 %13 时,余数为 j 的方案数
dp[i-1][j] -> dp[i][k]
k = j*10%13 (str[i] = 0)
k = (j*10+1) %13 (str[i] = 1)
从前往后推,可以依次推出方案数。
代码
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
#define int long long
//观察到13这个常数较小
//表示的正整数是13的倍数,即为该正整数%13为0
//因为 (x*10)%13 == (x%13)*10%13
// (x*10+1)%13 == ((x%13)*10+1)%13
//所以dp[i-1][j] -> dp[i][k]
//k = j*10%13(str[i] = 0)
//k = (j*10+1)%13(str[i] = 1)
//dpij代表前i位数,%13时余数为j的方案数
signed main()
{
string str;
cin>>str;
vector<vector<int>>dp(str.length(), vector<int>(13, 0));
//cout<<str.length()<<'\n';
int k;
dp[0][1] = 1;
int len = str.length();
for(int i = 1; i<len; i++)
{
for(int j = 0; j<=12; j++)
{
if(str[i] == '0'||str[i]=='?')
{
k = (j)*10%13;
dp[i][k] = (dp[i-1][j] + dp[i][k]) % mod;
}
if(str[i] == '1'||str[i]=='?')
{
k = (j*10+1)%13;
dp[i][k] = (dp[i-1][j] + dp[i][k]) % mod;
}
}
}
// for(int i = 0; i<=len-1; i++)
// {
// for(int j = 0; j<=12; j++)
// {
// cout<<dp[i][j]<<' ';
// }
// cout<<'\n';
// }
cout<<dp[len-1][0];
return 0;
}