熊猫(i)

题目描述

熊猫喜欢吃数,熊猫对与每个数都有他独特的评价。具体来说,熊猫对数 xx 的评价是个四元组 (a, b, c, d)(a,b,c,d),计算方式如下:

首先将 xx 写成二进制形式(不含前导零),然后将这作为一个字符串,那么 a =a= 子串 “00”00” 的数量,b =b= 子串 “01”01” 的数量,c =c= 子串 “10”10” 的数量,d =d= 子串 “11”11” 的数量。

现在熊猫想吃掉区间 [A,B] 之间所有评价是 (a, b, c, d)(a,b,c,d) 的数,由于你被熊猫抓了起来,所以他要你回答他能吃到多少个数。如果你回答不出,他就只好吃你。

输入格式

第一行一个 0101 串为 AA 的二进制表示。

第一行一个 0101 串为 BB 的二进制表示。

第三行四个数 a, b, c, da,b,c,d。

输出格式

一个数表示答案,对 10000000071000000007 取模。

样例

样例输入 1

10
1001
0 0 1 1

样例输出 1

1

数据范围与提示

子任务一(13pts):B ≤ 2^{20}B220。

子任务二(15pts):B ≤ 2^{100}B2100。

子任务三(19pts):B ≤ 2^{1000}B21000。

子任务四(15pts):A = 1, B = 2^k − 1A=1,B=2k1。

子任务五(38pts):无特殊限制。

对于所有的数据,1 ≤ A ≤ B ≤ 2^{100000}, a + b + c + d ≤ 10^51AB2100000,a+b+c+d105。

来源

2019年1月雅礼集训
 

solution
我们可以用abcd算出区间长,需要多少0(s0),这些0分成几段(n0),需要多少1(s1),这些1分成几段(n1),
我们先不考虑限制。
考虑插板法,0的方案为C(s0-1,n0-1)
方案数C(s0-1,n0-1)*C(s1-1,n1-1)
有限制的就从第1为开始像数位dp一样记上下界有没有顶满。
如果都没顶满就直接算。
这样效率就2n了
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 100005
#define mod 1000000007
#define ll long long
using namespace std;

int n,la,lb,a,b,c,d,n0,n1,s0,s1;
char A[maxn],B[maxn];
ll h[maxn],ny[maxn],ans;
ll work(ll a,int num){
    ll ans=1;
    while(num){
        if(num&1)ans=ans*a;
        a=a*a;a%=mod;ans%=mod;num>>=1;
    }
    return ans;
}
void pre(){
    n=100000;
    
    h[0]=1;for(int i=1;i<=n;i++)h[i]=h[i-1]*i%mod;
    ny[n]=work(h[n],mod-2);
    for(int i=n-1;i>=0;i--){
        ny[i]=ny[i+1]*(i+1)%mod;
    }
}
void Pd(){
    if(n>la){
        A[1]='1';for(int i=2;i<=n;i++)A[i]='0';
    }
    if(n<la){puts("0");exit(0);}
    if(n>lb){puts("0");exit(0);}
    if(n<lb){
        for(int i=1;i<=n;i++)B[i]='1';
    }
}
ll C(int N,int M){
    if(N<0||M<0||N<M)return 0;
    return h[N]*ny[M]%mod*ny[N-M]%mod;
}
void calc(int n0,int s0,int n1,int s1){
    ll w0=C(s0-1,n0-1),w1=C(s1-1,n1-1);
    if(s0==0&&n0==0)ans+=w1;
    if(s1==0&&n1==0)ans+=w0;
    ans=ans+w0*w1%mod;ans%=mod;
}
void solve(int i,int la,bool fa,bool fb,int n0,int s0,int n1,int s1){
    if((n0==0&&s0>0)||(n1==0&&s1>0))return;
    if(i==n+1){
        if(n0==1&&la==0&&!n1&&!s1&&!s0)ans++;
        if(n1==1&&la==1&&!n0&&!s0&&!s1)ans++;
        ans%=mod;
        return;
    }
    if(!fa&&!fb){
        calc(n0,s0,n1,s1);
        if(la==0)calc(n0-1,s0,n1,s1);
        if(la==1)calc(n0,s0,n1-1,s1);
        return;
    }
    
    if(s0<0||n0<0||s1<0||n1<0)return;
    if(i==1)solve(i+1,1,fa,fb,n0,s0,n1,s1-1);
    else {
        
        if(!fa||A[i]=='0'){
            if(la==1)solve(i+1,0,fa,fb&(B[i]=='0'),n0,s0-1,n1-1,s1);
            else solve(i+1,0,fa,fb&(B[i]=='0'),n0,s0-1,n1,s1);
        }
        if(!fb||B[i]=='1'){
            if(la==0)solve(i+1,1,fa&(A[i]=='1'),fb,n0-1,s0,n1,s1-1);
            else solve(i+1,1,fa&(A[i]=='1'),fb,n0,s0,n1,s1-1);
        }
    }
}

int main()
{
    pre();
    scanf(" %s",A+1);la=strlen(A+1);
    scanf(" %s",B+1);lb=strlen(B+1);
    
    scanf("%d%d%d%d",&a,&b,&c,&d);
    n=a+b+c+d+1;
    Pd();ans=0;
    if(b==c){
        n0=b;n1=n0+1;
        s0=a+n0,s1=d+n1;
        solve(1,0,1,1,n0,s0,n1,s1);
        printf("%lld\n",ans);
    }
    else if(b+1==c){
        n0=n1=c;
        s0=a+n0,s1=d+n1;
        solve(1,0,1,1,n0,s0,n1,s1);
        printf("%lld\n",ans);
    }
    else puts("0");
    return 0;
}
View Code
 

猜你喜欢

转载自www.cnblogs.com/liankewei/p/10604510.html