2019ICPC南昌 C - And and Pair
一:题目:
一个巨大的数 n 可表示为由0、1组成的字符串s,寻找可能的数对 ( i , j ) ,满足条件:
1:0 <= j <= i <= n
2: i & n = i
3: i & j = 0
求每个n最多有多少数对(i,j)
其中字符串S长度限定为 0 < = l e n g t h < = 1 0 5 0 <= length <= 10^5 0<=length<=105
样例1:S = 111 , num = 14
样例2:S = 1010,num = 15
二:分析
法一:找规律 + 二项式定理 + 快速幂预存
举个例子:S = 10010110
i & n = i : 字符串位上是0时,i 必须为0,当字符串位上是1时,i取值0,1均可
i & j = 0 : i,j位上不能同时存在1和1
通过枚举找规律可得 对于任意 i :j可行的个数为 2 i 2^i 2i个
当且仅当S的最高位为1时, i 的可能取值 为 100_0_ _0
这里面进行分类讨论:(i,j可能组合的个数)
其他位均为 0 : C 3 0 ∗ 2 7 C_{3}^{0} * 2^{7} C30∗27 (0的个数为7)
存在一个1: C 3 1 ∗ 2 6 C_{3}^{1} * 2^{6} C31∗26
存在两个1: C 3 2 ∗ 2 5 C_{3}^{2} * 2^{5} C32∗25
存在三个1: C 3 3 ∗ 2 4 C_{3}^{3} * 2^{4} C33∗24
sum = C 3 0 ∗ 2 7 + C 3 1 ∗ 2 6 + C 3 2 ∗ 2 5 + C 3 3 ∗ 2 4 C_{3}^{0} * 2^{7} + C_{3}^{1} * 2^{6} + C_{3}^{2} * 2^{5} + C_{3}^{3} * 2^{4} C30∗27+C31∗26+C32∗25+C33∗24
继续化简:
s u m = 2 4 ∗ ( C 3 0 ∗ 2 3 + C 3 1 ∗ 2 2 + C 3 2 ∗ 2 1 + C 3 3 ∗ 2 0 ) sum = 2^4 * (C_{3}^{0} * 2^{3} + C_{3}^{1} * 2^{2} +C_{3}^{2} * 2^{1} + C_{3}^{3} * 2^{0} ) sum=24∗(C30∗23+C31∗22+C32∗21+C33∗20)
由二项式定理得:
( x + 1 ) n = C n 0 X 0 + C n 1 X 1 + C n 2 X 2 + . . . + C n n X n (x + 1)^n = C_{n}^{0}X^0 + C_{n}^{1}X^1 + C_{n}^{2}X^2 + ... + C_{n}^{n}X^n (x+1)n=Cn0X0+Cn1X1+Cn2X2+...+CnnXn
故 s u m = 2 k ∗ 3 t sum = 2^{k} * 3^{t} sum=2k∗3t
其中 k = 除最高位以外 0 的个数
t = 除最高位以外 1 的个数
最后遍历字符串,针对为1的位置操作
注:快速幂nlogn预测 2 n , 3 n 2^n , 3^n 2n,3n
最后加 1 ,i = 0000时永远可行
AC代码
#include <bits/stdc++.h>
#define ll long long
#define maxn 100001
using namespace std;
const ll mod = 1000000007;
ll pow_2[maxn+10],pow_3[maxn+10];
ll power(ll a,ll b){
ll res = 1;
while(b){
if(b&1) res = res*a%mod;
a = a*a%mod;
b>>=1;
}
return res;
}
void init(){
for(int i=0;i<=maxn;i++){
pow_2[i] = power(2,i);
pow_3[i] = power(3,i);
}
}
int main(){
init();
int t;
string s;
cin>>t;
while(t--){
ll num0=0,num1=0,sum=0;
cin>>s;
for(int i=0;i<s.size();i++){
if(s[i]=='0') num0++;
else num1++;
}
for(int i=0;i<s.size();i++){
if(s[i]=='0'){
num0--;
continue;
}
else{
num1--;
sum = (sum + pow_2[num0] * pow_3[num1] % mod) % mod;
}
}
cout<<(sum+1) % mod<<endl;
}
return 0;
}
法二 : 数位DP
(待更…)