Codeforces Round #692 (Div. 2)D. Grime Zoo

(Prefix suffix + thinking + greedy)

D. Grime Zoo

Question portal:

D. Grime Zoo

Main idea:

Give you a composition consisting of '0' and '1' and'?', in which a 01 sub-sequence will produce x-point anger value. For every 10 subsequences, y points of anger will be generated. The question mark'?' can be changed to 0 or 1. Ask what the minimum sum of anger is.

Ideas:

After learning from the ideas of many people, I personally understand the idea better:
when the number of 0 and 1 in a sequence is fixed, the number of subsequences 00 and 11 is also fixed, and the number of subsequence 01+10 is also fixed. of. Then when x>y, we greedily want as few 01 as possible and as many 10 as possible, so we fill in 1 as far forward as possible. When x<y, we want as many 01 as possible and as few 10 as possible, so we fill in 1 as far as possible. See the code for specific implementation details.

AC Code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
char str[N];
LL x,y;
int st[N][3],ed[N][3];//记录每个位置之前0,1,'?'的数量
vector<int>g;//存下每个问号的位置
int main()
{
    
    
    scanf("%s",str+1);
    scanf("%lld%lld",&x,&y);
    int len=strlen(str+1);
    for(int i=1;i<=len;i++)
    {
    
    //求前缀
        st[i][0]=st[i-1][0];
        st[i][1]=st[i-1][1];
        st[i][2]=st[i-1][2];
        if(str[i]=='0') st[i][0]++;
        else if(str[i]=='1') st[i][1]++;
        else
        {
    
    
            st[i][2]++;
            g.push_back(i);
        } 
    }
    for(int i=len;i>=1;i--)
    {
    
    //求后缀
        ed[i][0]=ed[i+1][0];
        ed[i][1]=ed[i+1][1];
        ed[i][2]=ed[i+1][2];
        if(str[i]=='0') ed[i][0]++;
        else if(str[i]=='1') ed[i][1]++;
        else ed[i][2]++;
    }
    LL num0=0,num1=0;//记录前缀中0和1的数量(先把'?'都先看成是1)
    LL ans=0;
    for(int i=1;i<=len;i++)
    {
    
    
        if(str[i]=='0')
        {
    
    
            ans=ans+num1*y;
            num0++;
        }
        else
        {
    
    
            ans=ans+num0*x;
            num1++;
        }
    }
    LL res=ans;
    if(x<y)//10的愤怒值贡献高,所以我们尽量把1放在后面
    {
    
    
        for(int i=0;i<g.size();i++)//从前往后遍历每个问号的位置,并把它变成0
        {
    
    
            int idx=g[i];
            res=res-(st[idx-1][0]+st[idx-1][2])*x-ed[idx+1][0]*y;
            res=res+st[idx-1][1]*y+(ed[idx+1][1]+ed[idx+1][2])*x;
            ans=min(res,ans);
        }
    }
    else
    {
    
    //01的愤怒值高,所以我们尽量把1放前面
        for(int i=g.size()-1;i>=0;i--)
        {
    
    //从后往前遍历问号的位置,并把它变成0
            int idx=g[i];
            res=res-st[idx-1][0]*x-(ed[idx+1][0]+ed[idx+1][2])*y;
            res=res+(st[idx-1][1]+st[idx-1][2])*y+ed[idx+1][1]*x;
            ans=min(res,ans);
        }
    }
    printf("%lld\n",ans);
    //system("pause");
    return 0;
}

Guess you like

Origin blog.csdn.net/Stevenwuxu/article/details/111478266