zoukankan      html  css  js  c++  java
  • [USACO12FEB]牛的IDCow IDs 一题多解(求二进制中有k个1 ,第n大的数)

    题目:

    FJ给他的奶牛用二进制进行编号,每个编号恰好包含K 个"1" (1 <= K <= 10),且必须是1开头。FJ按升序编号,第一个编号是由K个"1"组成。

    请问第N(1 <= N <= 10^7)个编号是什么。

     

    不同寻常的暴力:

    样例是升序的第7个,我把1--7都列出来。

    1 1 1

    1 0 1 1

    1 1 0 1

    1 1 1 0

    1 0 0 1 1

    1 0 1 0 1

    1 0 1 1 0

    发现的规律是,每次将二进制串的从右往左数的第1个前面为0的1往左移一位。

    这个1右边的1全部靠后。  其实想想也很容易可以想出答案:既然我要移动1的位置了,那肯定是高位拉 , 那我后面的1就是反正最后咯,这样才可以是理论上的最小;

    a[i]表示的是第i个1的位置,初始值为(按阳历来说)第一个1的位置是1,第二个

    1的位置是2,第三个1的位置是3.二进制也就是1 1 1 。

    能移动的条件是,当前1的位置+1不等于

    下一个1的位置,也就是前面是空的。然后就这样啊....

    #include<cstdio>
    using namespace std;
    int n,k,j;
    int a[13];
    int main(){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=k;i++)a[i]=i;
        for(int i=2;i<=n;i++){
            j=1;
            while(1){
                a[j]++;
                if(a[j]!=a[j+1])break;
                a[j]=j;
                j++;
            }
        }
        j=k;
        for(int i=a[k];i>=1;i--){
            if(a[j]==i)printf("1"),j--;
            else printf("0");
        }
        return 0;
    }
    View Code

     

    组合数学法:(摘取一片博客 , 我还不是很qq理解)

    一个只有0和1的数字串,只有1对数字串大小有影响,0没有影响,大小取决于1的位置和数量。

    因为题目中要求出第n个编号是什么,并且这道题有一个限制:第一位必须是0,那么我们先将这个串用足够大小保存,足够大的话我们可以添加前导0,到最后从第一个非0位输出即可,也就是说我们要找到一个m,使得C(m,k) >= n,可以二分求m。

    当k=1直接特判掉。

    从大到小确定每一位。

    如果做到第i位,之前已经填了j个1,那么这一位填0的方案数就是C(i-1,k-j),即还剩i-1位可以填k-j个1的方案数。

    如果这个数小于n,那么这一位填1,并且n要减去这个数,否则这一位填0。

    不过这个组合数会非常大,还会爆long long,需要分类讨论进行二分求m.一定要注意这点,第一次提交就在这里wa的QwQ

    时间复杂度O(sqrt(n)k)

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int maxn = 10000010;
    long long n , k , m;
    long long num[maxn] , cnt;
    long long mid , l , r;
    long long zuhe(int x , int y)
    {
        long long k = 1;
        for(int i = x;i > x - y;i --)
        {
            k *= i;
        }
        for(int i = y;i > 1;i --)
        {
            k /= i;
        }
        return k;
    }
    int main(){
        scanf("%lld%lld" , &n , &k);
        if(k == 1)
        {
            for(int i = n;i > 0;i --)
            {
                if(i == n)
                {
                    printf("1");
                }
                else printf("0");
            }
            puts("");
            return 0;
        }
        else {
    //分类讨论二分求m
            if(k == 10)
            {
                l = 1;
                r = 600;
                while(l <= r)
                {
                    mid = (l + r) / 2;
                    if(zuhe(mid , k) >= n)
                    {
                        m = mid;
                        r = mid - 1;
                    }
                    else {
                        l = mid + 1;
                    }
                }
            }
            else {
                if(k >= 7)
                {
                    l = 1;
                    r = 1000;
                    while(l <= r)
                    {
                        mid = (l + r) / 2;
                        if(zuhe(mid , k) >= n)
                        {
                            m = mid;
                            r = mid - 1;
                        }
                        else {
                            l = mid + 1;
                        }
                    }
                }
                else {
                    l = 1;
                    r = 7000;
                    while(l <= r)
                    {
                        mid = (l + r) / 2;
                        if(zuhe(mid , k) >= n)
                        {
                            m = mid;
                            r = mid - 1;
                        }
                        else {
                            l = mid + 1;
                        }
                    }
                }
            }
            for(int i = m;i > 0;i --)
            {
                long long t = zuhe(i - 1 , k);
                if(t < n)
                {
                    num[i] = 1;
                    n -= t;
                    k --;
                    if(!cnt)
                    {
                        cnt = i;
                    }
                }
                if(!k || !n)
                {
                    break;
                }
            }
            for(long long i = cnt;i > 0;i --)
            {
                printf("%d" , num[i]);
            }
        }
       puts("");
        return 0;
    }
    View Code

     

    动态规划:

    太菜了没有想到组合数

    我们也医用数位dp去做;

    f[i][j] 表示在前i位我们放j个1的情况有几种

    f[i][j]=f[i-1][j]+f[i-1][j];

    然后我们直接大力的从字符串的高位开始枚举

    如果这个位子不放我们后来所有的方法都不够了那就放

    #include<bits/stdc++.h>
    #define Ll long long
    using namespace std;
    const Ll N=12,M=1e5+5;
    Ll a[M],f[M][N];
    Ll n,m,ok,v;
    int main()
    {
        scanf("%lld%lld",&m,&n);
        if(n==1){
            cout<<1;
            for(int i=1;i<m;i++)printf("0");
            return 0;
        }
        for(Ll i=0;i<=1e5;i++)f[i][0]=1;
        for(Ll i=1;i<=1e5;i++)if(!v)
            for(Ll j=1;j<=n;j++){
                f[i][j]=f[i-1][j]+f[i-1][j-1];
                if(j==n&&f[i][j]>=m){v=i;break;}
            }
        for(Ll i=v;i;i--){
            if(f[i-1][n]<m)
                a[i]=1,m-=f[i-1][n],n--;
            if(a[i])ok=1;
            if(ok)cout<<a[i];
        }
    }
    View Code

     

    组合数字最快然后超神暴力然后动态规划

  • 相关阅读:
    2020/10/25周总结
    软件需求---河北省重大需求进度报告05
    软件需求---河北省重大需求进度报告04
    软件需求---河北省重大需求进度报告03
    软件需求---河北省重大需求进度报告02
    解决js字符串传参未定义的问题
    软件需求---河北省重大需求进度报告
    2020/10/18周总结
    环信EaseUI集成IM即时通信
    第十二周学习进度总结
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/10033194.html
Copyright © 2011-2022 走看看