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

A. Add Odd or Subtract Even

题意:给两个数xy,每次对x加上一个奇数或者减去一个偶数,问从x变到y的最小操作次数。

分析:判断一下x和y的奇偶性讨论一下就可以了。

#include <bits/stdc++.h>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        int a,b;scanf("%d%d",&a,&b);
        if(a>b){
            printf("%d\n",((a&1)^(b&1))+1);
        }
        else if(a<b)printf("%d\n",(!((a&1)^(b&1)))+1);
        else printf("0\n");
    }
}

B. WeirdSort

题意:给定一个数组a,和一个数组p,对于任意i,可以交换a数组种pi 与pi + 1两个位置的数。问能否将a数组变为非降序。

分析:通过p数组确定若干个联通块,对每个联通块sort,然后判断a数组是否有序。

#include <bits/stdc++.h>
using namespace std;
int main(){
    int t;cin>>t;
    while(t--){
        int n,m;cin>>n>>m;
        vector<int>a(n+1),p(m+1);
        for (int i = 1; i <= n; ++i) {
            scanf("%d",&a[i]);
        }
        for (int i = 1; i <= m; ++i) {
            scanf("%d",&p[i]);
        }
        sort(p.begin()+1,p.end());
        p.erase(unique(p.begin()+1,p.end()),p.end());
        int fro=p[1],bak=p[1]+1;
        for (int i = 2; i <= m; ++i) {
            if(p[i]!=p[i-1]+1){
                sort(a.begin()+fro,a.begin()+bak+1);
                fro=p[i],bak=p[i]+1;
            }
            else bak=p[i]+1;
        }
        sort(a.begin()+fro,a.begin()+bak+1);
        bool ok = 1;
        for (int i = 2; i <= n; ++i) {
            if(a[i]<a[i-1])ok=0;
        }
        if(ok)puts("YES");
        else puts("NO");

    }
}

C. Perform the Combo

题意:给定一个字符串s和一个数组p,对于每个pi,遍历s中1-pi的字母,问每种字母遍历次数。

分析:差分。

#include <bits/stdc++.h>
using namespace std;
char s[200004];
int p[200004];
int a[200004];
int ans[26];
int main(){
    int t;
    cin>>t;
    while(t--){
        int n,m;scanf("%d%d",&n,&m);
        scanf("%s",s+1);
        for (int i = 0; i <= n; ++i) {
            a[i]=0;
        }
        for (int i = 0; i < 26; ++i) {
            ans[i]=0;
        }
        for (int i = 0; i < m; ++i) {
            scanf("%d",&p[i]);
            a[1]++,a[p[i]+1]--;
        }
        a[1]++;
        int sum = 0;
        for (int i = 1; i <= n; ++i) {
            sum+=a[i];
            ans[s[i]-'a']+=sum;
        }
        for (int i = 0; i < 26; ++i) {
            printf("%d ",ans[i]);
        }
        puts("");
    }
}

D. Three Integers

题意:给定3个数ABC,每次可以对任意一个数进行+1或者-1,问最少几次操作能使得A<=B<=C,并且A是B的因子,B是C的因子。

分析:暴力枚举,复杂度是一个调和级数。

#include <bits/stdc++.h>

using namespace std;
int main() {
    int t;
    cin >> t;
    while (t--) {
        int a, b, c;
        cin >> a >> b >> c;
        int ans = 2e9,aa,bb,cc;
        for (int i = 1; i <= 2e4; ++i) {
            for (int j = i; j <= 2e4; j+=i) {
                for (int k = j; k <= 2e4; k+=j) {
                    int temp = abs(a-i)+abs(b-j)+abs(c-k);
                    if(temp<ans){
                        ans = temp;
                        aa=i,bb=j,cc=k;
                    }
                }
            }
        }
        cout<<ans<<endl;
        cout<<aa<<' '<<bb<<' '<<cc<<endl;
    }
}

E. Construct the Binary Tree

题意:给定n,d,构造一棵n个点,各店深度之和为d的树。

分析:容易想到,n个点深度之和的上界是一条链,下界是一颗完全二叉树。

那么只需要计算出每个深度的点的个数就可以得到最终答案,可以计算得到一条链的sum为(n-1)*n/2,那么从深度最深的点开始遍历,每把这个点向上提一层,sum-1,那么只需要不断的把最深的点往上放就可以得到一个满足条件的答案。

#include <bits/stdc++.h>

using namespace std;
int dep[5004];
int ans[5004];
vector<int>v[5004];
int main(){
    int t;cin>>t;
    while(t--){
        int n,d;cin>>n>>d;
        for (int i = 0; i <= n; ++i) {
            v[i].clear();
        }
        int up = 0,dw = (n-1)*n/2;
        int num = 0;
        for (int i = 1; num <= n; i<<=1) {
            num += i;
            if(num <= n){
                up += log2(i)*i;
            }
            else {
                up += log2(i)*(i - num + n);
            }
        }
//        printf("%d %d\n",up,dw);
        if(d < up || d > dw){
            puts("NO");
            continue;
        }
        puts("YES");
        memset(dep,0, sizeof(dep));
        for (int i = 0; i < n; ++i) {
            dep[i]=1;
        }
        int now = dw,top = 1,pos = n-1;
        while(now > d){
            int nxt = max(pos - now + d,top);
            now -= pos - nxt;
            dep[pos]--;
            dep[nxt]++;
            pos --;

            if(dep[top] == dep[top-1]*2)top++;
        }
        int cnt = 2;
        v[0].push_back(1);
        for (int i = 1; dep[i] ; ++i) {
            for (int j = 1; j <= dep[i]; ++j) {
                ans[cnt]=v[i-1][(j-1)/2];
                v[i].push_back(cnt++);
            }
        }
        for (int i = 2; i <= n; ++i) {
            printf("%d ",ans[i]);
        }
        puts("");
    }
}

F. Moving Points

题意:n个点,每个点有一个pos和一个速度,D(U,V)为UV两点之间距离的最小值,求sum D(U,V)。

分析:对于任意两个点,其中一个点的两个属性都大于另一个点,那么其贡献为abs(pos1-pos2)。

对其中一维排序,另一维bit维护统计sum贡献即可。

#include <bits/stdc++.h>

using namespace std;

struct BIT {
    int n;
    vector<long long> v;

    BIT(int n) : n(n) { v.resize(n + 1); }

    void update(long long x, long long d) {
        while (x <= n) {
            v[x] += d;
            x += (x & -x);
        }
    }

    long long que(long long x) {
        long long res = 0;
        while (x > 0) {
            res += v[x];
            x -= (x & -x);
        }
        return res;
    }
};

BIT bit(200004),num(200004);
pair<int, int> p[200004];
unordered_map<int, int> mp;

int main() {
    int n;
    cin >> n;
    vector<int> v;
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &p[i].first);
    }
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &p[i].second);
        v.push_back(p[i].second);
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
    for (int i = 0; i < v.size(); ++i) {
        mp[v[i]] = i + 1;
    }
    sort(p + 1, p + n + 1);
    long long ans = 0;
    for (int i = n; i >= 1; --i) {
        ans += bit.que(mp[v[v.size()-1]]) -
               bit.que(mp[p[i].second]-1) -
               (num.que(mp[v[v.size()-1]]) - num.que(mp[p[i].second]-1))*(long long)(p[i].first - p[1].first);
        bit.update(mp[p[i].second],p[i].first - p[1].first);
        num.update(mp[p[i].second],1);
    }
    cout<<ans<<endl;
}
发布了176 篇原创文章 · 获赞 527 · 访问量 3万+

猜你喜欢

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