题目描述
熊猫喜欢吃数,熊猫对与每个数都有他独特的评价。具体来说,熊猫对数 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}B≤220。
子任务二(15pts):B ≤ 2^{100}B≤2100。
子任务三(19pts):B ≤ 2^{1000}B≤21000。
子任务四(15pts):A = 1, B = 2^k − 1A=1,B=2k−1。
子任务五(38pts):无特殊限制。
对于所有的数据,1 ≤ A ≤ B ≤ 2^{100000}, a + b + c + d ≤ 10^51≤A≤B≤2100000,a+b+c+d≤105。
来源
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 ",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 ",ans); } else puts("0"); return 0; }