zoukankan      html  css  js  c++  java
  • CTU Open 2018 Lighting /// 组合数递推 二进制

    题目大意:

    给定n k 给定一个数的二进制位a[]

    求这个数加上 另一个二进制位<=n的数b 后

    能得到多少个不同的 二进制位有k个1 的数

    样例
    input
    10 5
    1000100111
    output
    13

    10位的a 和 10位的b 相加得到c 
    b取值范围是 0000000000~1111111111
    所以 c取值范围是 1000100111~11000100110

    也就是求在这个范围里 有5个1的数 有多少个
     
    在这个取值范围里考虑两种情况
    10位时>= 1000100111
    11位时<=11000100110
     
    (1)10位时>= 1000100111

    要让数变大 考虑把0变为1 这样变化能保证得到的数绝对变大

    对于第一个0  
    10xxxxxxxx 变为11xxxxxxxx 
    x里必须再有3个1才能符合5个1的要求 所以方案数是 C(8,3)
    对于第二个0  100xxxxxxx 变为101xxxxxxx 
    方案数是C(7,3)
    对于第三个0  1000xxxxxx 变为1001xxxxxx
    方案数是 C(6,3)

    此时遇到了1 即到了10001xxxxx
    因为要保证>= 1000100111
    所以1必须固定不能变换
    那么 继续看下一个0

    100010xxxx 变为 100011xxxx
    方案数是C(4,2)
    1000100xxx 变为 1000101xxx
    方案数是C(3,2)
    然后1000100111本身也是一种方案

    会发现其实就是在0位累加组合数

       1   0     0    0  1     0     0  1  1  1

            C(8,3)+C(7,3)+C(6,3)   +C(4,2)+C(3,2)        +1(本身)

     所以10位的可能方案有 56+35+20+6+3+1=121 

    (2)11位时<=11000100110

    要让数变小 就考虑把1变为0 
    因为必须保证11位 所以默认第一位为1

    对于第二个1
    11xxxxxxxxx 变为 10xxxxxxxxx
    剩下的x中需要再有4个1 所以方案数是C(9,4)
    对于第三个1
    110001xxxxx 变为 110000xxxxx
    方案数是C(5,3)
    对于第四个1
    110001001xx 变为 110001000xx
    方案数是C(2,2)
    对于第五个1
    1100010011x 变为 1100010000x
    方案数是C(1,1)
    然后11000100110本身也是一种方案

     
    会发现其实就是在1位累加组合数

    1  1  0  0  0  1  0  0  1     1  0

        C(9,4)         +C(5,3)      +C(2,2)+C(1,1)   +1(本身)

    所以11位的可能方案有 126+20+1+1+1=149

    #include <bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define LL long long
    #define mem(i,j) memset(i,j,sizeof(i))
    #define inc(i,j,k) for(int i=j;i<=k;i++)
    #define dec(i,j,k) for(int i=j;i>=k;i--)
    const int N=1e3+5;
    const int mod=1e9+7;
    
    int n,k,a[N];
    char s[N];
    LL C[N][N];
    
    void init() {
        C[0][0]=C[1][0]=C[1][1]=1LL;
        inc(i,2,N-1) {
            C[i][0]=1LL;
            inc(j,1,i-1) {
                C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
            }
            C[i][i]=1LL;
        } 
    }
    
    int main()
    {
        init();
        while(~scanf("%d%d%s",&n,&k,s)) {
            int cnt=0;
            inc(i,0,n-1) {
                if(s[i]=='0')a[i]=0;
                else  a[i]=1, cnt++;
            }
    
            if(k==0) {
                if(cnt==0) printf("1
    ");
                else printf("0
    "); continue;
            }
            if(cnt==0) {
                printf("%d
    ",C[n][k]); continue;
            }
    
            LL ans=0;
            int U=k-1, D=n-1;
            inc(i,0,n-1) {
                if(U<0) break;
                if(a[i]==1) U--;
                else ans=(ans+C[D][U])%mod;
                D--;
            }
            if(cnt<=k) ans=(ans+1LL)%mod; // 本身
    
            reverse(a,a+n);
            inc(i,0,n-1) {
                a[i]+=1;
                if(a[i]>1) a[i+1]++;
                a[i]%=2;
            }
            reverse(a,a+n+1);
    
            U=k-1, D=n-1;
            inc(i,1,n) {
                if(U==0) break;
                if(a[i]==1) {
                    ans=(ans+C[D][U])%mod;
                    U--;
                }
                D--;
            }
            cnt=0;
            inc(i,0,n) if(a[i]==1) cnt++;
            if(cnt>=k) ans=(ans+1LL)%mod; // 本身
    
            printf("%lld
    ",ans);
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    二维码
    struts2 result type=(chain、dispatcher、redirect、redirect-action)
    hibernate bean注解
    js uploadify
    2进制转化成字符串
    server.xml
    html css
    页面乱码
    java class 路径问题
    table th td 宽度
  • 原文地址:https://www.cnblogs.com/zquzjx/p/10707265.html
Copyright © 2011-2022 走看看