zoukankan      html  css  js  c++  java
  • 2018 ICPC Asia Jakarta Regional Contest

    https://codeforc.es/gym/102001

    L Binary String

    签到题,给一个ll范围内的整数K,以及一个二进制串S,求从S中移除尽可能少的字符使得S表示的数不超过K。

    思路:贪心+dfs,首先优先移除最高位的1,假如移除这个1之后不会导致前导零出现,这样是最优的。否则,有两种选择,要么从后面移除最高的1或者没有1则随意移除一个0,要么把整个1000...0串移除,把新的1暴露出来,复杂度可能偏高。预处理一个上界,就是不进行移除前导零所得到的答案。有机会根据这个上界进行一定的最优性剪枝。但复杂度仍然玄学。事实上这个预处理出来的就是最优答案,因为删除1肯定比删除0要好,而优先删除高位1肯定更好。上面的两种路线事实上是重复了。一开始的思路就是对的,只是没开longlong溢出了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
     
    int ans;
     
    void dfs(ll n,string s,int cnt)
    {
        if(cnt>=ans)
            return;
        ll cur=0;
        for(int i=0; i<s.length(); ++i)
        {
            cur=(cur*2ll)+(s[i]-'0');
        }
        if(cur<=n)
        {
            ans=cnt;
            return;
        }
        if(s.length()>1&&s[1]=='1')
        {
            dfs(n,s.substr(1,s.length()),cnt+1);
        }
        else
        {
     
            for(int i=1; i<s.length(); ++i)
            {
                if(s[i]=='1')
                {
                    string t=s.substr(0,i)+s.substr(i+1,s.length());
                    dfs(n,t,cnt+1);
                    t=s.substr(i,s.length());
                    dfs(n,t,cnt+s.length()-t.length());
                    return;
                }
            }
     
            dfs(n,s.substr(0,s.length()-1),cnt+1);
            return;
        }
    }
     
    int main()
    {
    #ifdef local
        freopen("lyz.in","r",stdin);
    #endif // local
        ll n;
        while(cin>>n)
        {
            string s;
            cin>>s;
     
            string cs=s;
     
            ll cur=0;
            for(int i=0; i<s.length(); ++i)
            {
                cur=(cur*2ll)+(s[i]-'0');
            }
     
            int cnt=0;
            while(cur>n)
            {
                if(s.length()>1&&s[1]=='1')
                {
                    ++cnt;
                    s=s.substr(1,s.length());
                }
                else
                {
                    bool suc=0;
                    for(int i=1; i<s.length(); ++i)
                    {
                        if(s[i]=='1')
                        {
                            ++cnt;
                            string t=s.substr(0,i)+s.substr(i+1,s.length());
                            s=t;
                            suc=1;
                            break;
                        }
                    }
                    if(!suc)
                    {
                        ++cnt;
                        s=s.substr(0,s.length()-1);
                    }
                }
     
                cur=0;
                for(int i=0; i<s.length(); ++i)
                {
                    cur=(cur*2ll)+(s[i]-'0');
                }
                //cout<<s<<endl;
            }
     
            ans=cnt;
     
            dfs(n,cs,0);
     
            printf("%d
    ",ans);
        }
    }
    

    A. Edit Distance

    给一个二进制串S,求一个等长的二进制串T,使得S变为T至少要超过len(S)/2步。每步可以是增删改一个位置。

    首先0和1数量不等可以随便构造。等长的情况为什么要这样构造当时没有想清楚,但是感觉这样是对的。首先把开头元素反向,后面接一串反向串。比如原串是1开头的,就搞0111...1,原串是0开头的就搞1000...0,为什么会这样呢?

    首先原串串长必为偶数,设为2l,原串是1???...?,我构造0111...1,那么这个1必定要改成0或者删掉,花费至少为1。因为原串的1和0数量相等,所以原串后面有l个0,他们都要变成1,所以至少花费l+1步。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
     
    char s[300000];
    int main()
    {
    #ifdef local
        freopen("lyz.in","r",stdin);
    #endif // Yinku
        int T,n=0;
        while(~scanf("%s",s+1))
        {
            n=strlen(s+1);
            int o=0,y=0;
            for (int i=1; i<=n; i++)
            {
                if (s[i]=='1')
                    y++;
                else
                    o++;
            }
            if (y==1 && o==1)
                if (s[1]=='1')
                {
                    printf("01
    ");
                    continue;
                }
                else
                {
                    printf("10
    ");
                    continue;
                };
            if (y>o)
            {
                for (int i=1; i<=n; i++)
                    printf("0");
                printf("
    ");
            }
            else if (y<o)
            {
                for (int i=1; i<=n; i++)
                    printf("1");
                printf("
    ");
            }
            else if (y==o)
            {
                if (s[1]=='1')
                {
                    printf("0");
                    for (int i=1; i<=n-1; i++)
                        printf("1");
                    printf("
    ");
                }
                else
                {
                    printf("1");
                    for (int i=1; i<=n-1; i++)
                        printf("0");
                    printf("
    ");
                }
            }
        }
    }
    
  • 相关阅读:
    repair table
    rmtree函数
    alias 新的命令='原命令 -选项/参数'。举例说明,alias l=‘ls -lsh' 将重新定义 ls 命令,现在只需输入 l 就可以列目录了。
    MySQL DATE_SUB() 函数
    freebsd开启root远程登陆
    nbtscan ip地址
    FreeBSD 安裝 wget
    genlist -s 192.168.21.*
    /pentest/enumeration/0trace
    CSS的margin属性:详解margin属性
  • 原文地址:https://www.cnblogs.com/Inko/p/11462198.html
Copyright © 2011-2022 走看看