Codeforces Round #585 (Div. 2)简要题解

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_42671946/article/details/101021569

A - Yellow Cards

分析:分k1和k2的大小情况讨论一下就可以了。 

#include "bits/stdc++.h"
 
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 4;
struct BIT {
    int n;vector<int> v;
    BIT(int n) : n(n) { v.resize(n + 1); }
    void update(long long x, long long d) { while (x <= n) { v[x] += d;/*if (v[x] >= mod)v[x] -= mod*/;x += (x & -x); }}
    long long que(long long x) { long long res = 0;while (x > 0) { res += v[x];/*if (res >= mod)res -= mod*/;x -= (x & -x); }return res; }
};
long long qk(long long a, long long n) {
    long long res = 1;
    while (n) {
        if (n & 1)res = res * a % mod;
        n >>= 1;
        a = a * a % mod;
    }
    return res;
}
int a[maxn];
int main() {
    int a1,a2;
    int k1,k2;
    int n;
    cin>>a1>>a2>>k1>>k2>>n;
    int temp = a1*(k1-1) + a2*(k2-1);
    int mini = min(n - temp,a1+a2);
    int maxi = 0;
    if(mini <0)mini = 0;
    if(k1<k2){
        for (int i = 1; i <= a1; ++i) {
            if(n >= k1){
                maxi ++;
                n-=k1;
            }
        }
        for (int i = 1; i <= a2; ++i) {
            if(n >= k2){
                maxi ++;
                n-=k2;
            }
        }
    }
    else {
        for (int i = 1; i <= a2; ++i) {
            if(n >= k2){
                maxi ++;
                n-=k2;
            }
        }
        for (int i = 1; i <= a1; ++i) {
            if(n >= k1){
                maxi ++;
                n-=k1;
            }
        }
    }
    printf("%d %d\n",mini,maxi);
}

B - The Number of Products

分析:枚举左端点,用函数f(l)表示以l为左端点且满足条件的区间的个数。那么记录一下正数和负数的个数,z,f,如果第i个是正数,那么z--,否则f--,再swap(z,f)就可以了。

#include "bits/stdc++.h"
 
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 4;
struct BIT {
    int n;vector<int> v;
    BIT(int n) : n(n) { v.resize(n + 1); }
    void update(long long x, long long d) { while (x <= n) { v[x] += d;/*if (v[x] >= mod)v[x] -= mod*/;x += (x & -x); }}
    long long que(long long x) { long long res = 0;while (x > 0) { res += v[x];/*if (res >= mod)res -= mod*/;x -= (x & -x); }return res; }
};
long long qk(long long a, long long n) {
    long long res = 1;
    while (n) {
        if (n & 1)res = res * a % mod;
        n >>= 1;
        a = a * a % mod;
    }
    return res;
}
int a[maxn];
int main() {
    int n;
    cin>>n;
    for (int i = 1; i <= n; ++i) {
        scanf("%d",&a[i]);
        if(a[i]<0)a[i]=-1;
        else a[i]=1;
    }
    int z = 0,f = 0;
    int sum = 1;
    for (int i = 1; i <= n; ++i) {
        sum*=a[i];
        if(sum > 0)z ++;
        else f++;
    }
    long long ans = 0;
    for (int i = 1; i <= n; ++i) {
        ans += z;
        if(a[i] > 0){
            z--;
        }
        else {
            f--;
            swap(z,f);
        }
    }
    printf("%lld %lld\n",1LL*n*(n+1)/2 - ans,ans);
}

C - Swap Letters

分析:将a和b不同的地方记为一对pair,那么可能出现ab,ba两种情况。ab和ab可以通过一次操作完成,ba和ba也同理,ab和ba需要额外的一次操作,然后直接算一下就可以了。

#include "bits/stdc++.h"

using namespace std;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 4;
struct BIT {
    int n;vector<int> v;
    BIT(int n) : n(n) { v.resize(n + 1); }
    void update(long long x, long long d) { while (x <= n) { v[x] += d;/*if (v[x] >= mod)v[x] -= mod*/;x += (x & -x); }}
    long long que(long long x) { long long res = 0;while (x > 0) { res += v[x];/*if (res >= mod)res -= mod*/;x -= (x & -x); }return res; }
};
long long qk(long long a, long long n) {
    long long res = 1;
    while (n) {
        if (n & 1)res = res * a % mod;
        n >>= 1;
        a = a * a % mod;
    }
    return res;
}
int main() {
    string s,t;
    int n;
    cin>>n>>s>>t;
    vector<int>v1,v2;
    for (int i = 0; i < n; ++i) {
        if(s[i]==t[i])continue;
        else {
            if(s[i] == 'a')v1.push_back(1+i);
            else v2.push_back(1+i);
        }
    }
    if((int)(v1.size()+v2.size()) % 2 == 0){
        vector<pair<int,int>>ans;
        for (int i = 1; i < v1.size(); i+=2) {
            ans.push_back(make_pair(v1[i],v1[i-1]));
        }
        for (int i = 1; i < v2.size(); i+=2) {
            ans.push_back(make_pair(v2[i],v2[i-1]));
        }
        if(v1.size()&1){
            int pos1 = v1.size()-1,pos2 = v2.size()-1;
            ans.push_back(make_pair(v1[pos1],v1[pos1]));
            ans.push_back(make_pair(v1[pos1],v2[pos2]));
        }
        printf("%d\n",ans.size());
        for (int i = 0; i < ans.size(); ++i) {
            printf("%d %d\n",ans[i].first,ans[i].second);
        }
    }
    else puts("-1");
}

D - Ticket Game

分析:首先将问题抽象一下,将左边的数的和记为suml,右边的数的和记为sumr,左边的问号记为lt,右边的记为rt。

那么问题变为,最开始sum为sumr-suml。两个人轮流操作,每个人每次可以选择一种操作,减少0到9(最多lt次),或者增加0到9(最多rt次)。第一个人想让sum最后不等于0,第二个人想让最后等于0。

然后枚举一下几种情况就可以了。

最后可以发现,有效操作数可等效于rt与lt的差值,当(lt-rt)/2*9==sum的时候才有后手必胜。

#include "bits/stdc++.h"

using namespace std;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 4;
struct BIT {
    int n;vector<int> v;
    BIT(int n) : n(n) { v.resize(n + 1); }
    void update(long long x, long long d) { while (x <= n) { v[x] += d;/*if (v[x] >= mod)v[x] -= mod*/;x += (x & -x); }}
    long long que(long long x) { long long res = 0;while (x > 0) { res += v[x];/*if (res >= mod)res -= mod*/;x -= (x & -x); }return res; }
};
long long qk(long long a, long long n) {
    long long res = 1;
    while (n) {
        if (n & 1)res = res * a % mod;
        n >>= 1;
        a = a * a % mod;
    }
    return res;
}
int main() {
    int n;
    string s;
    cin>>n>>s;
    int lsum,lt,rsum,rt;
    lsum = lt = rsum = rt = 0;
    for (int i = 0; i < n/2; ++i) {
        if(s[i]=='?')lt++;
        else lsum += s[i]-'0';
    }
    for (int i = n/2; i < n; ++i) {
        if(s[i]=='?')rt++;
        else rsum += s[i]-'0';
    }
    int sum = rsum - lsum;
    bool ok;
    int temp = lt - rt;
    if(temp & 1)ok = 1;
    else {
        if(temp / 2 * 9 == sum)ok = 0;
        else ok = 1;
    }
    if(ok)puts("Monocarp");
    else puts("Bicarp");
}

E - Marbles

分析:用cost[i][j]表示,在只考虑ij两种颜色的情况下,把i全部移到j的前面的最小花费。这个只需要跑一遍就可以得到。

用dp[sta]表示在sta状态下(即只考虑sta中存在的几种颜色),使每种颜色各自独立所需的最小花费,那么枚举一下最后一次移动哪个颜色,记忆化跑一下就可以了。

#include "bits/stdc++.h"

using namespace std;
long long cost[22][22];
int a[400004];
long long dp[1 << 22];

long long dfs(int sta) {
    if (sta == 0)return 0;
    if (dp[sta] != -1)return dp[sta];
    long long ans = 1e18;
    for (int i = 1; i <= 20; ++i) {
        int temp = 1 << i;
        if (!(temp & sta))continue;
        int nxt = sta ^temp;
        long long sum = dfs(nxt);
        for (int j = 1; j <= 20; ++j) {
            int tem = (1 << j);
            if (tem & nxt)sum += cost[i][j];
        }
        ans = min(ans, sum);
    }
    return dp[sta] = ans;
}

int main() {
    memset(dp, -1, sizeof(dp));
    memset(cost, 0, sizeof(cost));
    int n;
    cin >> n;
    int num[22] = {0};
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        num[a[i]]++;
        for (int j = 1; j <= 20; ++j) {
            if (j == a[i])continue;
            cost[a[i]][j] += num[j];
        }
    }
    cout << dfs((1 << 21) - 2) << endl;
}

猜你喜欢

转载自blog.csdn.net/qq_42671946/article/details/101021569