Codeforces Round #590 (Div. 3)简要题解

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

A - Equalize Prices Again

分析:向上取整就可以了。

#include "bits/stdc++.h"

using namespace std;

int main() {
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        int sum=0,x;
        for (int i = 0; i < n; ++i) {
            cin>>x;
            sum+=x;
        }
        cout<<(sum+n-1)/n<<endl;
    }
}

B1 - Social Network (easy version)&&B2 - Social Network (hard version)

分析:用双端队列维护一下就可以了。另外我想知道这题是不是卡了hash。。。unordered_setT飞了。。。

#include "bits/stdc++.h"

using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    deque<int> q;
    set<int>s;
    for (int i = 0; i < n; ++i) {
        int x;
        scanf("%d",&x);
        if (s.count(x))continue;
        else {
            if (q.size() >= k){
                s.erase(q.back());
                q.pop_back();
            }
            q.push_front(x);
            s.insert(x);
    }
    }
    cout<<q.size()<<endl;
    while(q.size()){
        printf("%d ",q.front());
        q.pop_front();
    }
}

C - Pipes

分析:可以发现走的路线是唯一的,如果当前这个高度下一个格子是1或者2,那么只能直走,如果下一列格子的两个都是3456,那么会改变高度。所以模拟一下就可以了。

#include "bits/stdc++.h"
 
using namespace std;
char s[200004], t[200004];
 
int gai(char ch) {
    if (ch >= '3')return 2;
    else return 1;
}
 
int main() {
    int T;
    cin >> T;
    while (T--) {
        int n;
        scanf("%d", &n);
        scanf("%s%s", s, t);
        int now = 0;
        for (int i = 0; i < n; ++i) {
            if (gai(t[i]) == 2 && gai(s[i]) == 2)now ^= 1;
            else if (now == 0) {
                if (gai(s[i]) == 2) {
                    now = 0;
                    break;
                }
            } else if (now == 1) {
                if (gai(t[i]) == 2) {
                    now = 0;
                    break;
                }
            }
        }
        if (now)puts("YES");
        else puts("NO");
    }
}

D - Distinct Characters Queries

分析:对26个字母分别维护一下区间和就可以了,直接用bit就可以搞完。

#include "bits/stdc++.h"
 
using namespace std;
 
struct BIT {
    int n;
    vector<int> v;
 
    void init(int n){
        v.resize(n+1);
    }
    void update(int x, int d) {
        while (x <= n) {
            v[x] += d;
            x += (x & -x);
        }
    }
 
    int que(int x) {
        int res = 0;
        while (x > 0) {
            res += v[x];
            x -= (x & -x);
        }
        return res;
     }
}bit[26];
 
 
char s[100004];
 
int main() {
    for (int i = 0; i < 26; ++i) {
        bit[i].init(100004);
        bit[i].n = 100004;
    }
    scanf("%s",s+1);
    int n = strlen(s+1);
    for (int i = 1; i <= n; ++i) {
        bit[s[i]-'a'].update(i,1);
    }
    int q;
    cin>>q;
    while(q--){
        int op;
        scanf("%d",&op);
        if(op == 1){
            int pos;
            char val;
            scanf("%d %c",&pos,&val);
            bit[s[pos]-'a'].update(pos,-1);
            bit[val-'a'].update(pos,1);
            s[pos]=val;
        }
        else {
            int l,r;scanf("%d%d",&l,&r);
            int ans = 0;
            for (int i = 0; i < 26; ++i) {
                if(bit[i].que(r) > bit[i].que(l-1))ans++;
            }
            printf("%d\n",ans);
        }
    }
}

E - Special Permutations

分析:挺有意思的一道题。显然fp2可以通过fp1转移过来,fp1可以写成m-1个绝对值求和,转移到fp2只需要将fp1中的1变为2,2变为1,普遍一点就是fpn可以通过将fpn-1中的1变为n,n变为1来转移得到。同时显而易见的,对于一个数x,他只会被改变2次,即x->1->x+1,那么每次更新只需要把改变的值重新计算一下就可以了。

#include "bits/stdc++.h"

using namespace std;
int a[200004];
vector<int>v[200004];
pair<int,int>p[200004];
int main() {
    int n,m;
    cin>>n>>m;
    for (int i = 1; i <= m; ++i) {
        scanf("%d",&a[i]);
    }
    long long ans = 0;
    for (int i = 1; i < m; ++i) {
        ans += abs(a[i] - a[i+1]);
        p[i]=make_pair(min(a[i],a[i+1]),max(a[i],a[i+1]));
        if(a[i] == a[i+1])continue;
        v[a[i]].push_back(i);
        v[a[i+1]].push_back(i);
    }
    printf("%lld ",ans);
    for (int i = 2; i <= n; ++i) {
        for (int j = 0; j < v[1].size(); ++j) {
            ans -= abs(p[v[1][j]].first - p[v[1][j]].second);
            if(p[v[1][j]].first == 1)p[v[1][j]].first=i;
            if(p[v[1][j]].first > p[v[1][j]].second)swap(p[v[1][j]].first , p[v[1][j]].second);
            ans += abs(p[v[1][j]].first - p[v[1][j]].second);
        }
        for (int j = 0; j < v[i].size(); ++j) {
            ans -= abs(p[v[i][j]].first - p[v[i][j]].second);
            if(p[v[i][j]].first == i)p[v[i][j]].first=1;
            else if(p[v[i][j]].second == i)p[v[i][j]].second=1;
            if(p[v[i][j]].first > p[v[i][j]].second)swap(p[v[i][j]].first , p[v[i][j]].second);
            ans += abs(p[v[i][j]].first - p[v[i][j]].second);
        }
        swap(v[1],v[i]);
        printf("%lld ",ans);
    }
}

F - Yet Another Substring Reverse

分析:用dp[sta]表示sta这个状态的子串是否存在,可以在20*n的时间内求出dp数组。

那么我们要计算答案,朴素的想,枚举一个状态,然后取这个状态的补集,再枚举这个补集的子集,求两者和的最大值。那么我们可以预处理出每个状态的所有子集中的最大值,就可以O(1)转移了。

#include "bits/stdc++.h"
 
using namespace std;
char s[1000004];
int dp[1<<20];
int main() {
    scanf("%s",s);
    int n = strlen(s);
    memset(dp,0, sizeof(dp));
    for (int i = 0; i < n; ++i) {
        int now = 0;
        for (int j = i; j < n; ++j) {
            int x = (1<<(s[j]-'a'));
            if(now & x)break;
            else now |= x;
            dp[now]=j-i+1;
        }
    }
    for (int i = 1; i < (1<<20); ++i) {
        for (int j = 0; j < 20; ++j) {
            int x = 1 << j;
            if(!(i&x))continue;
            dp[i]=max(dp[i],dp[i - x]);
        }
    }
    int ans = 0;
    for (int i = 0; i < (1<<20); ++i) {
        ans =max(ans,dp[i] + dp[(1<<20)-1-i]);
    }
    cout<<ans<<endl;
}

猜你喜欢

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