The 16th Xidian University Program Design Competition Network Synchronization Competition - Xieldy And His Password (Looking for patterns/ideas)
Topic link: Xieldy And His Password
meaning of the title
As we all know, Xieldy's most commonly used password is ** .
In order to change this situation, he randomly created a string of 01, and intercepted a section from it as his own password.
The password he chooses satisfies the following conditions:
- The binary number represented by the password string can be represented as 3k (k>=0) in decimal.
The password string can have leading zeros.
Now that 01 strings have been randomly generated, he wants to know how many password schemes can be selected (different subsections are different).
Enter description:
若干组数据,每组数据仅一行01串s,表示random出来的的串,|s|<=1e6。
Output description:
输出口令的方案数。
idea one
Since the requirement of the title is to find a 01 string that can be divisible by three when it is converted into decimal, then we will find out what is the law of the binary representation of a multiple of three. Then, I started a long night of exploration. Unfortunately, I didn't find anything. However, after the competition, a classmate told me the law he found, that is, if a binary number is a multiple of three, then its A 1 in an odd and even digit must differ by a multiple of 3.
0 11 110 1001 10101 These examples all satisfy
Then we can think about it. I constructed a sum array with a size of three, and recorded the number of combinations of the previous parity difference of 0, 1, and 2; respectively.
for example
At 000000, the initial sum[0] = 1, sum[1] = sum[2] = 0;
In the process of moving to the left each time, calculate the current parity difference, if the difference is 0, access sum[0], the number of combinations related to the current bit is the number of the previous parity difference of 0 plus one
code one
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b) memset(a,b,sizeof(a))
typedef long long LL;
const int INF = (int)0x3f3f3f3f;
const LL MAXN = (LL)2e6+7;
char str[MAXN];
LL sum[3];
LL odd,eve;
LL ans;
void init(){
mmm(sum,0);
sum[0] = 1;
ans = 0;
odd = eve = 0;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
while (cin >> str){
init();
LL len = strlen(str);
rep(i,0,len-1){
if (i&1) odd += str[i]-'0';
else eve += str[i]-'0';
LL cha = ((odd-eve)%3+3)%3;//特别要注意这个操作,不能直接取绝对值,这样会破坏奇偶的差值
ans += sum[cha];
sum[cha] += 1;
}
cout << ans << endl;
}
}
idea two
Dynamic programming
01 String s, length n
dp[i][j]: Ended with s[i], the number of solutions that can be divided by 3 with remainder j (0<=i<=n1, 0<=j<= 2)
Update the dp array from left to right
If s[i] is '0', the number ending with s[i] is equivalent to the number ending with s[i1]*2
3k*2 = 6*k remainder 0
(3k+1)*2 = 6*k+2 remainder 2
(3k+2)*2 = 6*k+4 remainder 1
and then consider s[i] alone as a number 0 Case
So
dp[i].[0] = dp[i-1].[0]+1
dp[i].[1] = dp[i-1].[2]
dp[i].[2] = dp[i-1].[1]If s[i] is '1', the number ending with s[i] is equivalent to the number ending with s[i1]*2+1
3k*2+1 = 6*k+1 remainder 1
(3k+1)*2+1 = 6*k+3 remainder 0
(3k+2)*2+1 = 6*k+5 remainder 2
and then consider s [i] is the number 1 alone,
so
dp[i].[0] = dp[i-1].[1]
dp[i].[1] = dp[i-1].[0]+1
dp[i].[2] = dp[i-1].[2]
ans = Σdp[i].[0]
Time complexity O(n)
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)1e6+7;
char str[MAXN];
ll dp[MAXN][3];
ll sum;
void init(){
dp[0][0] = 0;
dp[0][1] = dp[0][2] = -1;
sum = 0;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
while (cin >> str+1){
init();
ll len = strlen(str+1);
rep(i,1,len){
if (str[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]+1;
dp[i][1] = dp[i-1][0];
dp[i][2] = dp[i-1][2];
}
sum += dp[i][0];
}
cout << sum << endl;
}
}