Codeforces Round #540 (Div. 3) A~F1题解

A. Water Buying

  • 题意
    1 L 1L 1L的饮用水需要 a a a 2 L 2L 2L的饮用水需要 b b b。你需要购买 n L nL nL水,问需要花费的最小代价。

  • 解题思路
    判断哪个更优即可,即 2 × a 2\times a 2×a b b b的大小。当然我们还需要考虑 n n n的奇偶性。

  • AC代码

/**
  *@filename:A
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-27 10:21
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;

int t;
ll n,a,b;
void solve(){
    if(a * 2 <= b){
        cout << n * a << endl;
    }
    else{
        cout << n / 2 * b + ((n % 2) ? a : 0) << endl;
    }
}
int main(){
    cin >> t;
    while(t -- ){
        cin >> n >> a >> b;
        solve(); 
    }
    return 0;
}

B. Tanya and Candies

  • 题意
    给你 n n n个糖果,移除其中一个糖果,使得剩下的奇数序号的糖果数总和等于偶数序号的糖果数总和。

  • 解题思路
    枚举每个糖果,利用前缀和处理达到 O ( 1 ) O(1) O(1)计算即可。注意移除了一个糖果后,后面的奇数位变偶数位置,偶数位置变奇数位置,注意细节处理。

  • AC代码

/**
  *@filename:B
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-27 10:26
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 200000 + 5;
const int P = 1e9+7;

int n,a[N];
ll pre_even[N],pre_odd[N];
void solve(){
    int ans = 0;
    for(int i = 1; i <= n; ++ i){
        if(pre_odd[i - 1] + pre_even[n] - pre_even[i] == pre_even[i - 1] + pre_odd[n] - pre_odd[i]){
            ans ++;
        }
    }
    cout << ans << endl;
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i){
        scanf("%d", &a[i]);
        if(i & 1){
            pre_odd[i] = pre_odd[i - 1] + a[i];
            pre_even[i] = pre_even[i - 1];
        }
        else{
            pre_odd[i] = pre_odd[i - 1];
            pre_even[i] = pre_even[i - 1] + a[i];
        }
    }
    solve();
    return 0;
}

C. Palindromic Matrix

  • 题意
    给你 n 2 n^2 n2个数,需要你将这些数填入 n × n n\times n n×n的矩阵中,使得其成为回文矩阵,即上下翻转左右反转和原矩阵相同。

  • 解题思路
    我们知道,对于 n n n为偶数的时候,其中矩阵总是四个四个对称的,所以我们只需要将这四个对称的填相同元素即可。而对于 n n n为奇数的时候,中间有一个十字,我们需要填充十字,那么条件就没有那么苛刻,中心点只需要填一个任意值,左右对称和上下对称需要填相同的元素即可。我们可以先填中心值,再填四个对称点,最后填剩下的十字。具体看AC代码。

  • AC代码

/**
  *@filename:C
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-27 10:38
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1000 + 5;
const int P = 1e9+7;

int n,cnt[N],x,a[22][22];
void solve(){
    //先判断n是否为奇数。如果是,直接将奇数放入a[(n + 1) / 2][(n + 1) / 2]
    if(n & 1){
        for(int i = 1; i < N; ++ i){
            if(cnt[i] & 1){
                a[(n + 1) / 2][(n + 1) / 2] = i;
                cnt[i] --;
                break;
            }
        }
        //将构建中间十字。
    }
    priority_queue<pair<int,int>,vector<pair<int,int> > > q;//利用优先队列实现。
    for(int i = 1; i < N; ++ i){
        if(cnt[i])q.push({cnt[i],i});
    }
    //构建对角。
    for(int i = 1; i <= n; ++ i){
        for(int j = 1; j <= n; ++ j){
            if(n % 2 && (i == (n + 1) / 2 || j == (n + 1) / 2))continue;
            if(!a[i][j] && !q.empty() && q.top().first >= 4){
                auto x = q.top();
                q.pop();
                a[i][j] = a[n - i + 1][j] = a[n - i + 1][n - j + 1] = a[i][n - j + 1] = x.second;
                x.first -= 4;
                if(x.first)q.push(x);
            }
        }
    }
    //注意中间十字是不会变的。我们先构建中间十字。
    if(n & 1){
        for(int i = 1; i <= n; ++ i){
            if(!a[i][(n + 1) / 2] && !q.empty() && q.top().first > 1){
                auto x = q.top();
                q.pop();
                a[i][(n + 1) / 2] = a[n - i + 1][(n + 1) / 2] = x.second;
                x.first -= 2;
                if(x.first)q.push(x);
            }
        }
        for(int j = 1; j <= n; ++ j){
            if(!a[(n + 1) / 2][j] && !q.empty() && q.top().first > 1){
                auto x = q.top();
                q.pop();
                a[(n + 1) / 2][j] = a[(n + 1) / 2][n - j + 1] = x.second;
                x.first -= 2;
                if(x.first)q.push(x);
            }
        }
    }
    bool flag = true;
    if(!q.empty())flag = false;
    if(flag){
        cout << "YES" << endl;
        for(int i = 1; i <= n; ++ i){
            for(int j = 1; j <= n; ++ j){
                cout << a[i][j] << " ";
            }
            cout << endl;
        }
    }
    else{
        cout << "NO" << endl;
    }
}
int main(){
    cin >> n;
    for(int i = 1; i <= n * n; ++ i){
        cin >> x;
        cnt[x] ++;
    }
    solve();
    return 0;
}

D1 D2. Coffee and Coursework

  • 题意
    给你 n n n杯咖啡,每杯咖啡都有一个值 a i a_i ai。当你一天内依次喝的咖啡得到的值为 a 1 , m a x ( 0 , a 2 − 1 ) . . . m a x ( 0 , a k − k + 1 ) a_1,max(0,a_2-1)...max(0,a_k-k+1) a1,max(0,a21)...max(0,akk+1)。问你需要几天才可以得到 m m m

  • 解题思路
    很明显的二分题,我们知道当所有咖啡值总和小于 m m m时是一定无解的。我们又注意到,若 x x x天可行,那么 x + 1 x+1 x+1天必定可行。若 x x x天不可行,那么 x − 1 x-1 x1天必定不可行。据此,符合二分的性质,所以我们二分天数,在计算得到的值时我们从大到小按天数依次分配即可,这样减小最大损耗。

  • AC代码

/**
  *@filename:D1
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-27 11:49
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 2e5 + 5;
const int P = 1e9+7;

int n,m;
ll a[N],ans;
bool check(int day){
    //为了最少消耗,我们均分day。
    ll ans = 0,cnt = 1,c = 0;
    while(true){
        for(int d = 1; d <= day && cnt <= n; ++ d){
            ans += max(1LL * 0,a[cnt ++] - c);
        }
        c++;
        if(cnt > n)break;
    }
    return ans >= m;
}
void solve(){
    sort(a + 1, a + 1 + n,greater<int>() );
    //此原理就是尽可能的浪费一些也可以行。ans为最大的数量。
    if(ans < m){
        cout << - 1 << endl;
    }
    else{
        int l = 1, r = n;
        while(l < r){
            int mid = (l + r) >> 1;
            if(check(mid)){
                r = mid;
            }
            else{
                l = mid + 1;
            }
        }
        cout << l << endl;
    }
}
int main(){
    cin >> n >> m;
    for(int i= 1; i <= n; ++ i){
        cin >> a[i];
        ans += a[i];
    }
    solve();
    return 0;
}

E. Yet Another Ball Problem

  • 题意
    n n n对舞者,其中一男一女,设它们的服装颜色分别为 b i , g i b_i,g_i bi,gi。有 k k k种颜色的舞服。现在需要你分配一种服装方案使得:

    1. 所有舞者的颜色都是这 k k k种之一。
    2. 没有一对舞者的服装一摸一样,即不会存在 i ≠ j , b i = b j    a n d    g i = g j i≠j,b_i=b_j \space \space and \space \space g_i=g_j i=j,bi=bj  and  gi=gj
    3. 一对舞者内的二人服装不一样。
    4. 相邻序号的舞者中两个男的和女的的服装不一样。即 b i ≠ b i + 1 , g i ≠ g i + 1 b_i≠b_{i+1},g_i≠g_{i+1} bi=bi+1,gi=gi+1
  • 解题思路
    我们知道,根据第 2 2 2点和第三点,我们能构造出来的舞者队服为 k × ( k − 1 ) k\times (k -1) k×(k1),当其值小于 n n n时自然不可能,否则一定可行。那么我们只需要再满足第四点即可,我们可以依次构造 ( 1 , 2 ) ( 2 , 1 ) ( 1 , 3 ) ( 3 , 1 ) . . . ( i , j ) ( j , i ) (1,2)(2,1)(1,3)(3,1)...(i,j)(j,i) (1,2)(2,1)(1,3)(3,1)...(i,j)(j,i)这种即可达到要求。

  • AC代码

/**
  *@filename:E
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-27 18:46
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;

int n,k;
void solve(){
    ll ans = 1LL * k * (k - 1);
    if(ans < n){
        cout << "NO" << endl;
    }
    else{
        cout << "YES" << endl;
        int idx = 1,cnt = 0;
        while(true){
            for(int i = idx + 1; i <= k; ++ i){
                if(cnt < n){
                    cout << idx << " " << i << endl;
                    cnt ++;
                }
                if(cnt < n){
                    cout << i << " " << idx << endl;
                    cnt ++;
                }
                if(cnt == n)break;
            }
            idx ++;
            if(cnt == n){
                break;
            }
        }
    }
}
int main(){
    cin >> n >> k;
    solve();
    return 0;
}

F1. Tree Cutting (Easy Version)

  • 题意
    给你一个无向树,每个顶点都有一个点权,其中 0 0 0表示未染色, 1 1 1表示染了红色, 2 2 2表示染了蓝色。你需要删除一条边分成两个集合后,每个集合中的点只包含了一种颜色。问方案数。

  • 解题思路
    d f s dfs dfs遍历树,我们需要存储每个结点的子树及其本身的颜色信息。那么当这个颜色信息中只包含了一种颜色即可行。按这种思想遍历即可。

  • AC代码

/**
  *@filename:F
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-27 19:02
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 300000 + 5;
const int P = 1e9+7;

int n,a[N],r[N],b[N];
vector<int> g[N];
ll ans;
void dfs(int u,int fu){
    if(a[u] == 1){
        r[u] ++;
    }
    else if(a[u] == 2){
        b[u] ++;
    }
    for(auto &v : g[u]){
        if(v != fu){
            dfs(v,u);
            //将子节点的数量加起来。
            b[u] += b[v];
            r[u] += r[v];
            if(b[v] == b[0] && !r[v] || r[v] == r[0] && !b[v]){
                ans ++;
            }
        }
    }
}
void solve(){
    dfs(1,0);
    cout << ans << endl;
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i){
        scanf("%d", &a[i]);
        //1:red 2:blue
        //统计所有的红蓝结点数,相当于0是祖先。
        if(a[i] == 1){
            r[0] ++;
        }
        else if(a[i] == 2){
            b[0] ++;
        }
    }
    int u,v;
    for(int i = 1; i < n; ++ i){
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    solve();
    return 0;
}
posted @   unique_pursuit  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示