C - And and Pair
题意:
问有多少组(i,j)满足要求。
 要求为:
 0<=j<=i<=n
 i&n=i
 i&j=0
 答案mod 1e9+7
题解:
这个和我的思路时一样的,且讲的更清楚
 i&n=i说明n为0的地方,i必须为0;n为1的地方,i随意(两种选择)
 i&j=0说明i为1的地方,j必须为0;i为0的地方,j随意(两种选择)
 j还要<=i
 所以我的思路:
 对于一组S:101010
 我们从前往后开始扫,第一位为1时,我们可以认为i在这一位是1,对于j的取值,因为j在i为0的地方随便取,后面5位中,最少有3个0,最多有5个0(因为1的位置i是随便取得,i可以选1)
 那么对于i为10x0x0(x表示这位有两种情况),我们可以确定j的情况,j为0x?x?x,(x表示有两种选择,?表示要根据i的情况定)
 这个情况的答案就是:
 0的个数为3个:C20 *23
 0的个数为4个:C21 *24
 0的个数为5个:C22 *25
 求和:
 sum=C20 *23+C21 *24+C22 *25
 我们把23提出来:
 sum=23 (C20 *20+C21 *21+C22 *22)=23 (2+1)2
 (用的二项式定理,比赛时没想到:)
 (x+1)n= (Cn0 *x0+Cn1 *x1+…+Cnn *xn)
 现在将结论推广:
 设k为后面0的数量
 t为后面1的数量
 答案就是sum=2k 3t
 遍历字符串,不断更新k和t,然后取和
代码:
#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++;//0的数量 else num1++;//1的数量 }for(int i=0;i<s.size();i++){if(s[i]=='0'){num0--;//除了最高位0的数量 continue;}else{num1--;//除了最高位1的数量 sum = (sum + pow_2[num0] * pow_3[num1] % mod) % mod;}}cout<<(sum+1) % mod<<endl;}return 0;
}