给定一个非常大的非负整数n,计算满足以下条件的整数对
(
i
,
j
)
(i\,,j)
(i,j)的个数:
1
、
0
≤
j
≤
i
≤
n
;
1、0≤j≤i≤n;
1、0≤j≤i≤n;
2
、
i
&
n
=
i
;
a
n
d
2、i\&n=i;and
2、i&n=i;and
3
、
i
&
j
=
0
3、i\&j=0
3、i&j=0
二项式
在二进制的情况下,
因为
i
&
n
=
i
i\&n=i
i&n=i,所以:只有当n某一位为1时,i在这一位才能为1。
因为
i
&
j
=
0
i\&j=0
i&j=0,所以:当i某一位为1时,j在这一位只能为0;当i某一位为0时,(保证
j
<
i
j<i
j<i的情况下)j在这一位可以为0也可以为1。
为保证 j ≤ i j≤i j≤i以及整数对不重合,我们可以从低位到高位,算出i的每一位固定为1时(当然是前提可以为1时),整数对 ( i , j ) (i\,,j) (i,j)的个数:
如:n=10010110010110,我们固定i中倒数第8位为1,即0000001xxxxxxx。
在n的后面的7位中有3位为1。当i中这三位都为1时:因为i某一位为0时,j在这一位可以为0也可以为1,所以整数对个数为
C
3
3
×
2
4
C_{3}^3×2^4
C33×24;当i中有两位为1时,整数对个数为
C
3
2
×
2
5
C_{3}^2×2^5
C32×25;当i中有一位为1时,整数对个数为
C
3
1
×
2
6
C_{3}^1×2^6
C31×26;当i后面7位全为0时,整数对个数为
C
3
0
×
2
7
C_{3}^0×2^7
C30×27。
s
u
m
=
C
3
0
×
2
7
+
C
3
1
×
2
6
+
C
3
2
×
2
5
+
C
3
3
×
2
4
=
C
3
0
×
2
4
+
C
3
1
×
2
5
+
C
3
2
×
2
6
+
C
3
3
×
2
7
=
2
4
(
C
3
0
×
2
0
+
C
3
1
×
2
1
+
C
3
2
×
2
2
+
C
3
3
×
2
3
)
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^4+C_{3}^1×2^5+C_{3}^2×2^6+C_{3}^3×2^7=2^4(C_{3}^0×2^0+C_{3}^1×2^1+C_{3}^2×2^2+C_{3}^3×2^3)
sum=C30×27+C31×26+C32×25+C33×24=C30×24+C31×25+C32×26+C33×27=24(C30×20+C31×21+C32×22+C33×23),通过观察可以发现前面幂的次数是前面n中0的个数,组合数的个数是前面n中1的个数。然后我们可以用二项式定理求出后面的一项:
或者找规律:通过下面规律递推就可以得出
∑
i
=
0
n
C
n
i
×
2
i
\sum _{i=0}^n C _{n}^i×2^i
∑i=0nCni×2i的值
#include<algorithm>
#include<iostream>
//#include<stdio.h>
#include<vector>
#include<string>
#include<cstring>
#include<map>
using namespace std;
#define int long long
const int manx=1e5+10;
const int manx2=1e7+10;
const int mod=1e9+7;
signed main()
{
ios::sync_with_stdio(false);
int t;
char str[manx];
cin>>t;
while(t--)
{
cin>>str;
int ans=0,mul=1,temp=1;
int len=strlen(str);
for(int i=len-1;i>=0;i--)
{
if(str[i]=='1')
{
(ans+=(mul*temp))%=mod;
(temp+=temp*2)%=mod;
}
else
(mul*=2)%=mod;
}
cout<<ans+1<<endl;//还有i和j都为0的情况
}
return 0;
}
dp
根据:
1、只有当n某一位为1时,i在这一位才能为1;2、当i某一位为1时,j在这一位只能为0;当i某一位为0时,(保证
j
<
i
j<i
j<i的情况下)j在这一位可以为0也可以为1。
直接递推,碰到n某一位为1时,加上dp[ ][1][0]的值(同前面说的i某位固定为1是,整数对的个数)
#include<algorithm>
#include<iostream>
//#include<stdio.h>
#include<vector>
#include<string>
#include<cstring>
#include<map>
using namespace std;
#define int long long
const int manx=1e5+10;
const int manx2=1e7+10;
const int mod=1e9+7;
int dp[manx][2][2];
signed main()
{
ios::sync_with_stdio(false);
int t;
char str[manx];
cin>>t;
while(t--)
{
cin>>str;
memset(dp,0,sizeof dp);
int ans=0,len=strlen(str);
if(str[len-1]=='1')
dp[len-1][1][0]=dp[len-1][0][1]=dp[len-1][0][0]=1;
else dp[len-1][0][1]=dp[len-1][0][0]=1;
ans+=dp[len-1][1][0];
for(int i=len-2;i>=0;i--)
{
if(str[i]=='1')
dp[i][1][0]=dp[i][0][1]=dp[i][0][0]=(dp[i+1][1][0]+dp[i+1][0][1]+dp[i+1][0][0])%mod;
else dp[i][0][1]=dp[i][0][0]=(dp[i+1][1][0]+dp[i+1][0][1]+dp[i+1][0][0])%mod;;
(ans+=dp[i][1][0])%=mod;
}
cout<<ans+1<<endl;
}
return 0;
}