2019ICPC南昌站C.And and Pair


题意:

  给一个二进制数n,求满足0<=j<=i<=n且i&&n==i&&i&j==0的数对(i,j)有多少对,n可能有前导0.

解析:

  对一一个特定的i(例如0101010)来说,设从低位到最高位的1之间有x个0,可选择的j就是2x种(i为0的位置j可以选0/1,i为1的位置j为0),从低位向高位枚举每个数字,当遇到1时,让他做最高位的1,设这个1的低位中有y个1和x个0,简单推导得到有2x*∑Cyi2i=2x*3y种方案。(∑Cni2i值得一提的是这个的物理意义就是枚举每个子集的每个子集,是子集dp的时间复杂度)

代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
const int mod=1e9+7;
const int maxn=1e5+10;
ll num2[maxn];
ll num3[maxn];
char a[maxn];

int main(){
    ll t;
    scanf("%lld",&t);
    getchar();
    num2[0]=num3[0]=1;
    for(int i=1;i<maxn;i++){
        num2[i]=(num2[i-1]*2)%mod;
        num3[i]=(num3[i-1]*3)%mod;
    }
    while(t--){
        scanf("%s",a);
        ll len=strlen(a);
        ll y,x;
        y=x=0;
        ll num=0;
        for(ll i=len-1;i>=0;i--){
            if(a[i]=='1'){
                num=(num+(num2[x]*num3[y])%mod)%mod;
                y++;
                //printf("%lld %lld %lld \n",num2[x],num3[y],num);
            }
            else x++;
        }
        num=(num+1)%mod;//只算了i的最高位位1的情况,要算上i==0的情况
        printf("%lld\n",num);
    }
    return 0;
}

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM