2015/2/19
遞推。
給定一個區間內有多少個數,數的二進制中0的數量不比1少。
範圍決定不能暴力(顯而易見的)
利用遞推求區間和的方式
區間【L, R】 -> 最後的形式是 Sum(R) - Sum(L - 1)
問題來了,如何求Sum(X)?
我選擇的方式是,
輸入N, M ,(以N爲例) 把N轉換成二進制 len爲N 的二進制長度。
遞推 (1 ~ len )位數的二進制數中滿足條件的數有幾個。
比如:2進制 2位數 中滿足題目的數只有一個 10. 4位數 4個 1000 1001 1100 1010(然後去組合數學吧)這部分可以打表
然後麻煩的地方在於 10 -> 1010 ,如果你把i = 4 的情況算進去 ,那麼有1100 符合算法 卻不符合題意 1100-12 >10 ;
所以i = len 的情況還要獨自考慮下。
遍歷二進制數,從高位往低位,遇到1即可將其變成0,然後在計算下 1->0的時候之前位上的變化有幾種。
反正很煩就對了(你打我呀)。
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<climits>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
#define mod 10007
#define lson pos<<1,l,mid
#define sc(n) scanf("%d",&n)
#define rson pos<<1|1,mid+1,r
#define pr(n) printf("%d\n",n)
#define met(n,m) memset(n, m, sizeof(n))
#define F(x,y,i) for(int i = x;i > y; i--)
#define f(x,y,i) for(int i = x;i < y; i++)
#define ff(x,y,i) for(int i = x;i <= y; i++)
#define FF(x,y,i) for(int i = x;i >= y; i--)
const int N=100500;
const int inf = INT_MAX;
int Max(int a,int b)
{
return a>b?a:b;
}
int Min(int a,int b)
{
return a<b?a:b;
}
int a1[1005],a2[1005];
int ans[35];
int turn(int x,int y)
{
__int64 sum = 1;
__int64 dum = 1;
__int64 nnm = 1;
f(0, y , i)
{
nnm *=(x - i);
dum *= i+1;
}
return (int)(nnm/dum) ;
}
int turn_0(int x)
{
int num = x/2 - 1;
__int64 sum = 1;
__int64 dum = 1;
__int64 nnm = 1;
f(0, num , i)
{
nnm *=(x -1 - i);
dum *= i + 1;
sum+=nnm/dum;
}
return (int)(sum);
}
int main()
{
int n, m, tot, x;
ans[0] = ans[1] = 0;
f(2,35,i)
{
ans[i] = turn_0(i);
}
f(2,35,i)ans[i] += ans[i-1];
while(~scanf("%d%d",&m,&n))
{
int cnt1 = 0,cnt2 = 0;
int sum1 = 0,sum2 = 0;
int one1 = 0,one2 = 0;
while(n)
{
a1[cnt1++] = n%2;
if(a1[cnt1-1])one1++;
n/=2;
}
m--;
while(m)
{
a2[cnt2++] = m%2;
if(a2[cnt2-1])one2++;
m/=2;
}
sum1 = ans[cnt1-1];
sum2 = ans[cnt2-1];
if(cnt1>1&&cnt1 >= one1*2)sum1++;
if(cnt2>1&&cnt2 >= one2*2)sum2++;
f(0,cnt1-1,i)
{
if(a1[i])
{
one1--;
if(cnt1 >= one1*2)sum1++;
int num = cnt1/2 - one1;
num = Min(num,i);
f(1,num+1,j)
{
sum1 += turn(i,j);
}
}
}
f(0,cnt2-1,i)
{
if(a2[i])
{
one2--;
int num = cnt2/2 - one2;
if(cnt2 >= one2*2)sum2++;
num = Min(num,i);
f(1,num+1,j)
{
sum2 += turn(i,j);
}
}
}
printf("%d\n",sum1 - sum2);
}
return 0;
}