zoukankan      html  css  js  c++  java
  • 题解 CF1399D 【Binary String To Subsequences】

    题目链接:http://codeforces.com/contest/1399/problem/D
    题目描述:

    You are given a binary string s consisting of n zeros and ones.
    Your task is to divide the given string into the minimum number of subsequences in such a way that each character of the string belongs to exactly one subsequence and each subsequence looks like "010101 ..." or "101010 ..." (i.e. the subsequence should not contain two adjacent zeros or ones).
    Recall that a subsequence is a sequence that can be derived from the given sequence by deleting zero or more elements without changing the order of the remaining elements. For example, subsequences of "1011101" are "0", "1", "11111", "0111", "101", "1001", but not "000", "101010" and "11100".
    You have to answer t independent test cases.

    Input

    The first line of the input contains one integer t (1≤t≤2⋅(10^4)) — the number of test cases. Then t test cases follow.
    The first line of the test case contains one integer n (1≤n≤2⋅ (10^5)) — the length of s. The second line of the test case contains n characters '0' and '1' — the string s.
    It is guaranteed that the sum of n does not exceed 2⋅ (10^5) (∑n≤2⋅(10^5)).

    Output

    For each test case, print the answer: in the first line print one integer k (1≤k≤n) — the minimum number of subsequences you can divide the string s to. In the second line print n integers (a_1),(a_2),…,(a_n) (1≤(a_i)≤k), where (a_i) is the number of subsequence the i-th character of s belongs to.
    If there are several answers, you can print any.

    最开始的朴素做法(这种做法会TLE):
    用一个数组c来存储每个子序列最后的数字,在遍历数组a的同时使(a_i)遍历数组c,使其接上满足题意的子序列。如果没有找到,(a_i)单独作为一个子序列。用(b_i)来记录(a_i)是属于第几个子序列的,因为是保序的,只需令(b_i)=j+1就行了。

    #include<iostream>
    #include<vector>
    using namespace std;
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int t;
        cin>>t;
        while(t--)
        {
            int n;
            char x;
            cin>>n;
            vector<int> a(n+5),b(n+5),c;
            for(int i=1;i<=n;i++)
            {
                cin>>x;
                a[i]=x-'0';
            }
            
            c.push_back(a[1]);
            b[1]=1;
            for(int i=2;i<=n;i++)
            {
                int len=c.size();
                bool flag=true;
                for(int j=0;j<len;j++)
                {
                    if(a[i]+c[j]==1)
                    {
                        c[j]=a[i];
                        b[i]=j+1;
                        flag=false;
                    }
                    if(flag==false)
                    break;
                }
                if(flag==true)
                {
                    c.push_back(a[i]);
                    b[i]=len+1;
                }
            }
            cout<<c.size()<<endl;
            //cout<<"n=="<<n<<endl;
            for(int i=1;i<=n;i++)
               cout<<b[i]<<" ";
            cout<<endl;
            c.clear();
            //cout<<"c.size()=="<<c.size()<<endl;
        }
        return 0;
    }
    

    正确做法:上面的朴素做法会TLE的根本原因在于对于每一个(a_i)都要遍历一遍数组c,这样时间复杂度就上去了,而实际上我们只需要对每个(a_i)判断当前已经存在的子序列中是否有以1结尾的子序列或以0结尾的子序列即可。而不需要每次遍历。因此我们用两个数组分别来存取以0或1结尾的子序列就可以了。这时为了确定(b_i)的值,我们需要对两个数组中所存储的值进行修改,应该存储的是每个子序列的编号,而不再是0或1了。

    #include<iostream>
    #include<vector>
    #include<string>
    using namespace std;
    string s;
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int t;
        cin >> t;
        while (t--)
        {
            int n;
            cin >> n >> s;
            vector<int> b(n + 5), c0, c1;
            for (int i = 0;i < n;i++)
            {
                int newpos;
                if (s[i] == '0')
                {
                    newpos = c0.size() + c1.size();
                    if (c1.empty())
                    {
                        c0.push_back(newpos);
                    }
                    else
                    {
                        newpos = c1.back();
                        c1.pop_back();
                        c0.push_back(newpos);
                    }
                }
                else
                {
                    newpos = c0.size() + c1.size();
                    if (c0.empty())
                    {
                        c1.push_back(newpos);
                    }
                    else
                    {
                        newpos = c0.back();
                        c0.pop_back();
                        c1.push_back(newpos);
                    }
                }
                b[i] = newpos + 1;
            }
            cout << c0.size() + c1.size() << endl;
            for (int i = 0;i < n;i++)
                cout << b[i] << " ";
            cout << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    Ubuntu 代理及系统信息修改
    名词解释
    第一章 用标准I/O函数将标准输入复制到标准输出 1-3
    Viewpager模仿微信主布局的三种方式 ViewPager,Fragment,ViewPager+FragmentPagerAdapter
    github入门到上传本地项目
    安卓界面篇(一) 自定义一个topbar
    ace布置小作业: 制作一个简单的电话号码归属地查询软件:JSON解析和Volly发送get请求
    android json解析及简单例子
    Volly框架的使用基础版及使用中的一些坑 Ace 网络篇(三)
    Android清单文件详解(三)----应用程序的根节点<application>
  • 原文地址:https://www.cnblogs.com/Acapplella/p/13452829.html
Copyright © 2011-2022 走看看