poj 3252--Round Numbers

    技术2025-08-05  26

    c(n,m) 表示从n个里取出m的组合数。

    对于一个二进制数(b位)。其首位为1.则RN数1.当b为偶数b=2k时, RN=c(2k-1,2k-1)+c(2k-1,2k-2)+...+c(2k-1,k+1);

    由c(2k-1,0)=c(2k-1,2k-1);  c(2k-1,1)=c(2k-1,2k-2);  ...  c(2k-1,k-1)=c(2k-1,k+1);

    c(2k-1,0)+c(2k-1,1)+....+c(2k-1,k-1)+c(2k-1,k)+c(2k-1,k+1)+...+c(2k-1,2k-2)+c(2k-1,2k-1)=2^(2k-1);

    即有RN+c(2k-1,k)+RN=2^(2k-1)

    所以RN=[2^(2k-1)-c(2k-1,k)]/2;

    即RN=[2^(b-1)-c(b-1,b/2)]/2;

    2.当b为奇数b=2k+1时,RN=c(2k,2k)+c(2k,2k-1)+...+c(2k,k);

    按1的思路,可得,RN=[2^(2k)]/2=[2^(b-1)]/2=2^(b-2);

    --------------------------分割线----------------------------

    问题归结于求<=n的RN(Round Numbers)个数。

    1.把n转化为二进制,低位到高位->a[],位数为->index.2.位数少于index的,即1,2,3 ,... ,index-1  用上面的方面解决。3.位数为index的,遍历a[],用p,q记录遇到的0,1个数。由i=(index-1)->0 遇到1(不是index-1)则处理,就是找出把当前的1变成0的所有RN数:由剩下的长度(即右边二进制位)为i。1的个数为q,0的个数为p+1(第i个位置是0的)。则RN数有,RN=c(i,i)+c(i,i-1)+..+c(i,k) ;  (!!!k的范围!!!!: k+p+1>=i-k+q && k>=0)

    注:2,3的RN数之和就是n的RN数。

     

     

    Source Code Problem: 3252 User: liuyuquan100 Memory: 264K Time: 32MS Language: C++ Result: Accepted Source Code #include<iostream> using namespace std; int pos[31][31]; int index[31]; int a[32]; int solve(int n) { int i,j=0,m; m=n; do{a[j++]=m%2; m=m>>1; } while(m); m=1; for(i=j-2;i>0;i--) { if(i%2) m+=index[i]/2; else m+=(index[i]-pos[i][i/2])/2; } int p,q,k; p=0;q=1; for(i=j-2;i>=0;i--) { if(a[i]==0) p++; else { for(k=i;k>=0&&k+p+1>=i-k+q;k--) { m+=pos[i][k]; } q++; } } if(p>=q) m++; return m ; } int main() { int i,j; for(i=0;i<31;i++) pos[i][0]=pos[0][i]=1; for(i=1;i<31;i++) { for(j=1;j<=i;j++) { if(i==j) pos[i][j]=1; else pos[j][i]=pos[i][j]=pos[i-1][j]+pos[i-1][j-1]; } } index[0]=1; for(i=1;i<31;i++) index[i]=index[i-1]*2; while(cin>>i>>j) { cout<<solve(j)-solve(i-1)<<endl; } return 0 ; }

    最新回复(0)