POJ 3252 遞推關係

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;  
}  
	



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章