Codeforces Round #633 (Div. 2)

本文深入解析了四道算法竞赛题目,包括A.FillingDiamonds的菱形填充计数,B.SortedAdjacentDifferences的排序与相邻差值优化,C.PoweredAddition的最小值加法策略,以及D.EdgeWeightAssignment的树状结构边权分配问题。通过对每道题目的详细分析和代码实现,展示了算法设计与优化的思维过程。

A. Filling Diamonds

分析一下就可以发现要你输出的是可以有多少种竖着的菱形,而且竖着的菱形只能有一个,所以可以得出结论,输入n输出n

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define INF 1ll<<60
const int maxn = 1e2+10;
int main(){
    int t;
    scanf("%d", &t);
    for(int p = 1; p <= t; p++){
        int n;
        scanf("%d", &n);
        printf("%d\n", n);
    }
    return 0;
}

B. Sorted Adjacent Differences

题意很清楚,给你一个长度为n的数组,对其重新排列,使得满足|a1−a2|≤|a2−a3|≤…≤|an−1−an|这样的等式。
思路:首先sort一遍,然后从中间开始一左一右开始选,符合前面的不等式。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define INF 1ll<<60
const int maxn = 1e5+10;
ll a[maxn];
int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        int n;
        scanf("%d", &n);
        rep(i, 0, n){
            scanf("%lld", &a[i]);
        }
        sort(a, a+n);
        int mid = n/2;
        int l = mid-1, r = mid+1;
        printf("%lld ", a[mid]);
        while(l!=-1 || r!=n){
            if(l!=-1) printf("%lld ", a[l--]);
            if(r!=n) printf("%lld ", a[r++]);
        }
        printf("\n");
    }
    return 0;
}

C. Powered Addition

想要加的是最小值,则可以这么想,minn = a[i]前的最大值-a[i], 然后在minn中取最大值,所要输出的值为minn的二进制的最高位。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define INF 1ll<<60
const int maxn = 1e5+10;
ll a[maxn];
int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        int n;
        scanf("%d", &n);
        rep(i, 0, n){
            scanf("%lld", &a[i]);
        }
        ll minn = 0, ma = a[0];
        rep(i, 1, n){
            minn = max(ma-a[i], minn);
            ma = max(ma, a[i]);
        }
        ll ans = 0;
        while(minn){
            minn /= 2;
            ans++;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

D. Edge Weight Assignment

题意:给你一棵树,然后给每条边赋值,使得叶子节点之间经过的路径的权值异或和为零,问你赋予这些路径的权值最少可以有多少种不同的数字,最多可以有多少种不同的数字。
思路:对于最小值如果两个叶子节点之间存在经过奇数条边的最小值即为3,否则为1,对于最大值,初始值为n-1,即n-1条边,如果存在两个叶子节点公用一个结点则最大值减一,最后可得答案。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define INF 1ll<<60
const int maxn = 1e5+10;
vector<int> v[maxn];
int flag = 0;
int x;
int vis[maxn];
void dfs(int step, int ans){
    if(v[step].size()==1){
        if(ans%2!=0) flag = 1;
        //printf("%d ", ans);
        return ;
    }
    for(int i = 0; i < v[step].size(); i++){
        if(vis[v[step][i]]==0){
            vis[v[step][i]] = 1;
            dfs(v[step][i], ans+1);
            vis[v[step][i]] = 0;
        }
    }
}
int main(){
    int n;
    scanf("%d", &n);
    rep(i, 0, n-1){
        int x, y;
        scanf("%d%d", &x, &y);
        v[x].push_back(y);v[y].push_back(x);
    }
    rep(i, 1, n+1){
        if(v[i].size()==1){
            x=i;
            vis[i] = 1;vis[v[i][0]] = 1;
            dfs(v[i][0], 1);
            break;
        }
    }
    if(flag) printf("3 ");
    else printf("1 ");
    int sum = 0;
    rep(i, 1, n+1){
        int ans = 0;
        if(v[i].size()>=2)
        rep(j, 0, v[i].size()){
            if(v[v[i][j]].size()==1){
                ans++;
            }
        }
        if(ans>=2) sum += ans-1;
    }
    printf("%d\n", n-1-sum);
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值