链接:https://www.nowcoder.com/acm/contest/107/E
来源:牛客网
题目描述
众所周知,Xieldy最常用的口令是******。
为了改变这一现状,他random了一个01串,并从中截取了一段作为自己的口令。
他选择的口令满足以下条件:
1. 口令串表示的二进制数在十进制下可以被表示为3k(k>=0)。
2. 口令串可以有前导零。
现已经random出了01串,他想知道有多少种口令方案可以选择(不同的子段即为不同)。
为了改变这一现状,他random了一个01串,并从中截取了一段作为自己的口令。
他选择的口令满足以下条件:
1. 口令串表示的二进制数在十进制下可以被表示为3k(k>=0)。
2. 口令串可以有前导零。
现已经random出了01串,他想知道有多少种口令方案可以选择(不同的子段即为不同)。
输入描述:
若干组数据,每组数据仅一行01串s,表示random出来的的串,|s|<=1e6。
输出描述:
对于每组数据,输出一个数,表示最少的缺页次数。
示例1
输入
101010
输出
5
01字符串s,长度为n
dp[i][j]:以s[i]结尾,能得到被 3 除余 j 的方案数(0<=i<=n1,0<=j<=2)
从左往右更新dp数组
若s[i]为‘0’,以s[i]结尾的数字相当于以s[i1]结尾的数字*2
3k*2 = 6*k 余0
(3k+1)*2 = 6*k+2 余2
(3k+2)*2 = 6*k+4 余1
再考虑s[i]独自成数字0的情况
故
dp[i][0] = dp[i1][0]+1
dp[i][1] = dp[i1][2]
dp[i][2] = dp[i1][1]
若s[i]为‘1’,以s[i]结尾的数字相当于以s[i1]结尾的数字*2+1
3k*2+1 = 6*k+1 余1
(3k+1)*2+1 = 6*k+3 余0
(3k+2)*2+1 = 6*k+5 余2
再考虑s[i]独自成数字1的情况
故
dp[i][0] = dp[i1][1]
dp[i][1] = dp[i1][0]+1
dp[i][2] = dp[i1][2]
ans = Σdp[i][0]
时间复杂度O(n)
#include<bits/stdc++.h>
#define maxn 1000010
#define ll long long
using namespace std;
ll dp[maxn][3];
int main()
{
char s[maxn];
while(scanf("%s",s+1)!=EOF)
{
int l=strlen(s+1);
memset(dp,0,sizeof(dp));
ll sum=0;
for(int i=1;i<=l;i++)
{
if(s[i]=='0')
{
dp[i][0]=dp[i-1][0]+1;
dp[i][1]+=dp[i-1][2];
dp[i][2]+=dp[i-1][1];
}
else
{
dp[i][0]+=dp[i-1][1];
dp[i][1]=dp[i-1][0]+1;
dp[i][2]+=dp[i-1][2];
}
sum+=dp[i][0];
}
cout<<sum<<endl;
}
return 0;
}