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

题目:http://codeforces.com/contest/950/problem/C

题意:把一个字符串s,切割成0 010 01010 这样的子串,也就是0开头,0结尾的01交替串。

这题我改进了几次自己的算法才过的。不过开始没打算写博客。但是后来看到一个大佬的算法。决定批判一下自己的思考方法。

首先说说自己做这题的思路。
很明显的贪心嘛。0101010这样取。然后再取第二串。然后第一串肯定是最长的。然后根据这个写。优化就可以比如说第二个查到i了。可以更具上一串01的编码位置来让他少搜索后面的。并且因为第一串的长度一定大于等于后面的。所以也可以优化。然后放代码吧。不难理解。

#include<bits/stdc++.h>
#define INF 1e18
#define inf 1e9
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define IOS ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
const int _max = 200000+50;
const ll mod = 1000000007;
vector<int> v[_max];
string s;
bool t[_max];
int main(){ 
    IOS;
    cin>>s;
    memset(t,true,sizeof(t));
    int cnt = 0,len = s.length();
    int i = 0;
    while(len){
        bool pre = 1;
        if(cnt >= 1) i = v[cnt-1][0];
        while(!t[i]) i++;
        if(s[i] != '0'){
            cnt = -1;
            break;
        }
        while(i < s.length()){
            len--;
            pre = !pre;
            v[cnt].push_back(i+1);
            t[i] = false;
            if(cnt >= 1 && v[cnt].size() < v[cnt-1].size())
                i = max(i+1,v[cnt-1][v[cnt].size()]);
            if(cnt >= 1 && v[cnt].size() == v[cnt-1].size()) break;
            while(!t[i] || pre==s[i]-'0') i++;
        }
        if(!(v[cnt].size()&1)){
            cnt = -1;
            break;
        }
        cnt++;
    }
    cout<<cnt<<endl;
    if(cnt == -1) return 0;
    for(int x = 0 ; x < cnt ; x++){
        cout<<v[x].size()<<' ';
        for(int y = 0 ; y < v[x].size()-1 ; y++)
            cout<<v[x][y]<<' ';
        cout<<v[x][v[x].size()-1]<<endl;
    }
    return 0;
}

好了。接下来是大佬的算法。没有改直接贴过来。


/*char s[201000];
vector<int> a[201111];
int main()
{
    scanf("%s",s);
    int n=strlen(s);
    int k=0,len=0;
    for(int i=0;i<n;i++)
    {
        if(s[i]=='0')
        {
            k++;
            a[k].push_back(i+1);
            len=max(len,k);
        }
        else
        {
            if(k==0)
            {
                printf("-1\n");
                return 0;
            }
            a[k].push_back(i+1);
            k--;
        }
    }
    if(len!=k)
        printf("-1\n");
    else
    {
        printf("%d\n",k);
        for(int i=1;i<=k;i++)
        {
            int temp=a[i].size();
            printf("%d",temp);
            for(int j=0;j<temp;j++)
            printf(" %d",a[i][j]);
            printf("\n");
        }
    }
    return 0;
}*/

仔细看了的就肯定发现了。大佬的代码和我的代码就是两个思考方式。我是找第一串最长的。这也是大多数人的思考方式。但是,这样就会浪费搜索一些重复字符的时间。要让节约时间,就要把这些搜索也充分利用起来。因为00是只能分开两个存的。所以完全可以同时开vector来存啊。这样换了思路方式之后其实我们只要把这个串遍历一遍就可以出答案了。其实想到了这样贪心就很简单了。但是平时的思维还是太凝固了。以后要注意。有时候要多想想别的办法!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值