Codeforces Round #469 (Div. 2)C. Zebras(贪心)

C. Zebras
time limit per test1 second
memory limit per test512 megabytes
inputstandard input
outputstandard output
Oleg writes down the history of the days he lived. For each day he decides if it was good or bad. Oleg calls a non-empty sequence of days a zebra, if it starts with a bad day, ends with a bad day, and good and bad days are alternating in it. Let us denote bad days as 0 and good days as 1. Then, for example, sequences of days 0, 010, 01010 are zebras, while sequences 1, 0110, 0101 are not.

Oleg tells you the story of days he lived in chronological order in form of string consisting of 0 and 1. Now you are interested if it is possible to divide Oleg’s life history into several subsequences, each of which is a zebra, and the way it can be done. Each day must belong to exactly one of the subsequences. For each of the subsequences, days forming it must be ordered chronologically. Note that subsequence does not have to be a group of consecutive days.

Input
In the only line of input data there is a non-empty string s consisting of characters 0 and 1, which describes the history of Oleg’s life. Its length (denoted as |s|) does not exceed 200 000 characters.

Output
If there is a way to divide history into zebra subsequences, in the first line of output you should print an integer k (1 ≤ k ≤ |s|), the resulting number of subsequences. In the i-th of following k lines first print the integer li (1 ≤ li ≤ |s|), which is the length of the i-th subsequence, and then li indices of days forming the subsequence. Indices must follow in ascending order. Days are numbered starting from 1. Each index from 1 to n must belong to exactly one subsequence. If there is no way to divide day history into zebra subsequences, print -1.

Subsequences may be printed in any order. If there are several solutions, you may print any of them. You do not have to minimize nor maximize the value of k.
题意:给你一个由0,1组成的字符串,要求把它分成任意个子串,每个子串必须0,1交替出现并且由0开头由0结束。输出分成的子串个数,以及子串中每个元素的下标。
思路:(有些啰嗦,可直接看代码)考虑对于每个1有两种处理方法,第一,放在已合法的子串后并在其后加一个0,代价为1。第二,给它分配2 个0,一个在前一个在后,构成新的子串。代价为2。题目说了,单独的0是一个合法的子串,那么我们只需要将每个1处理完,就可以了。所以我们可以贪心的用最小代价去处理每个1,保证合法答案一定有解。
贪心的思路确定了,那么是算法,如果我们每一次去扫描一遍字符串,并找出最长的合法子串。这样好像能够达到要求,但在最坏情况下即,00000…111111…00000。这样的数据下显然会超时。
我用n个vector来储存答案,那么初始条件下它们看上去像这样:
v1 ←
v2
v3

然后我们定义一个头指针,指向v1,如图箭头。开始扫描字符串,如果第一个是0:
v1 0
v2 ←
v3

第二个是1:
v1 0 1 ←
v2
v3

显然,对于当前字符串,如果是0,那么我们把他放在当前指针位置,并把指针下移。如果是1,指针上移。如果指针向上出界即无解,如果最终指针没有在最下面,无解。子串的个数即指针值的峰值。o(n)复杂度。
代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define met(s,k) memset(s,k,sizeof s)
#define scan(a) scanf("%d",&a)
#define scanl(a) scanf("%lld",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannl(a,b) scanf("%lld%lld",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define prin(a) printf("%d\n",a)
#define prinl(a) printf("%lld\n",a)
using namespace std;
typedef long long ll;
const  int maxn=2e6+10;
char s[maxn];
int ans=1,flag,cont;
vector<int >v[maxn];
int main()
{
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0;i<len;i++)
    {
        if(s[i]=='0')
        {
            v[cont++].push_back(i+1);
            if(cont>ans)ans=cont;
        }
        if(s[i]=='1')
        {
            if(cont<=0||i==len-1)
            {
                flag=1;
                break;
            }
            v[--cont].push_back(i+1);
        }
    }
    if(flag==1||cont!=ans)printf("-1");
    else
    {
        prin(ans);
        for(int i=0;i<ans;i++)
        {
            int len=v[i].size();
            printf("%d ",len);
            for(int j=0;j<len;j++)printf("%d ",v[i][j]);
            printf("\n");
        }
    }
    return  0;
}

猜你喜欢

转载自blog.csdn.net/swust5120160705/article/details/79505214