Educational Codeforces Round 160 (Rated for Div. 2) 题解A~D

发布时间 2023-12-19 20:17:21作者: 橙之夏

Educational Codeforces Round 160 (Rated for Div. 2)

A. Rating Increase

纯暴力,分割字符串,如果n1<n2就输出,如果遍历完整个数组都不存在n1<n2就输出-1.

const int N = 2e5 + 10;

int toint(string s)
{
    stringstream ss;
    ss << s;
    int v;
    ss >> v;
    return v;
}

void solve()
{
    string s;
    cin >> s;
    for (int i = 0; i < s.size(); i++)
    {
        if ((i<s.size()-1 && s[i+1] != '0') || i==s.size()-1)
        {
            int n1 = toint(s.substr(0, i+1));
            int n2 = toint(s.substr(i + 1));
            if (n1 < n2)
            {
                cout << n1 << " " << n2 << endl;
                return;
            }
        }
    }
    cout << "-1" << endl;
}

B. Swap and Delete

贪心题目,可以先遍历整个字符串,统计0和1的个数,然后再次遍历整个字符串,碰到1就用0填,0就用1填,直到0和1中有一个消耗完,则说明此后所有的字符都应该删掉,答案即为n-i

const int N = 2e5 + 10;

void solve()
{
    string s;
    cin >> s;
    int n1 = 0, n2 = 0;
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='0') n1++;
        else n2++;
    }
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='1') n1--;
        else n2--;
        if(n1 <0 || n2<0) 
        {
            cout << s.size() - i<<endl;
            return;
        }
    }
    cout << 0 << endl;
}

C. Game with Multiset

首先用一个数组存入所有的2的i次方的个数,例如w[2]表示2的2次方的个数,然后每次要验证一个数是否可以由现有的数构成时,先拷贝一份w,然后从低位向高位二进制枚举要合成的数a的每一位(因为低位可以合成高位,但是高位无法分解成低位),如果a的i位为1且w[i]>=1,则将w[i]--(用于合成),并且将w[i]除以二加到他的高一位上去,若w[i]==0,则说明无法合成,输出-1,如果遍历完w数组,则说明可以合成,返回true

int w[32];

void solve()
{
    int op,a;
    cin >> op >> a;
    if(op==1)
    {
        w[a]++;
    }
    else
    {
        int bak[32];
        memcpy(bak,w,sizeof w);
        for(int i=0;i<31;i++)
        {
            if(a&1)
            {
                if(bak[i])
                {
                    bak[i]--;
                }
                else
                {
                    puts("NO");
                    return;
                }
            }
            a >>= 1;
            if(i<30)
                bak[i+1] += bak[i]/2;
        }
        puts("YES");
    }
}

D. Array Collapse

dp,题解看注释

#define int long long
const int N = 3e5 + 10, MOD = 998244353;
//dp(i,0/1)表示是否选择第i个数,last_min(i)表示1~i-1中最接近nums[i]的小于nums[i]的数的下标,sum[i]表示前i个数中可达数组的sum
int dp[N][2], last_min[N], sum[N];
int nums[N];
int n;

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++) //初始化
    {
        cin >> nums[i];
        last_min[i] = 0;
        sum[i] = 0;
        dp[i][0] = dp[i][1] = 0;
    }
    stack<int> stk; //单调栈,用于处理last_min
    for (int i = 1; i <= n; i++)
    {
        while (stk.size() && nums[stk.top()] > nums[i]) //如果栈顶大于nums[i]则全部pop
            stk.pop();
        if (stk.size()) //如果栈顶存在小于nums[i]的数,那么他一定是最接近nums[i]的数
            last_min[i] = stk.top();
        stk.push(i); //入栈
    }
    dp[0][0] = 1;
    sum[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        if (last_min[i]) //如果存在比nums[i]小的数
        {
            //如果要选nums[i],那么应该减去包含last_min[i]的部分(因为如果存在last_min[i],肯定不存在nums[i],
            //因为last_min[i]一定比nums[i]小,这会导致nums[i]一定会被删掉)
            //同时如果不包含last_min[i]了,还应该加上不选last_min[i]的数量,也就是dp[last_min[i]][0]
            dp[i][1] = (sum[i - 1] - sum[last_min[i] - 1] + dp[last_min[i]][0] + MOD) % MOD;
            //如果不选nums[i],则说明肯定选了last_min[i]或者更小的部分,因此直接加上last_min的全部情况即可
            dp[i][0] = (dp[last_min[i]][1] + dp[last_min[i]][0]) % MOD;
        }
        else //如果不存在比nums[i]小的数,则说明nums[i]一定可以选上,而且相当于方案数就是sum[i-1]
        {
            dp[i][1] = sum[i - 1];
        }
        //累加方案总数
        sum[i] = (sum[i - 1] + dp[i][1]) % MOD;
    }
    cout << (dp[n][0] + dp[n][1]) % MOD << endl;
}