codeforces竞赛1114题解

A. Got Any Grapes?

AC代码:

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner cin=new Scanner(System.in);
        int x = cin.nextInt();
        int y = cin.nextInt();
        int z = cin.nextInt();
        int a = cin.nextInt();
        int b = cin.nextInt();
        int c = cin.nextInt();
        boolean f = true;
        if(a < x){
            f = false;
        }else{
            a -= x;
            int d = a + b;
            if(d < y){
                f = false;
            }else{
                d -= y;
                if(d + c < z){
                    f = false;
                }
            }
        }
        System.out.println(f?"YES":"NO");
        cin.close();

    }
}

B. Yet Another Array Partitioning Task

题目大意:

对于一个长度为n的数组,将它划分为k个子数组,每个子数组不少于m个元素,子数组中前m大的元素和被称为这一子数组的美丽度,求这k个子数组的美丽度的和。

解题思路(贪心):

就是求这个数组的前k*m大的元素之和。
解题步骤:

  1. 将数组的值和下标作为pair键值对,放入到vector中排序(按照值的大小排序)
  2. 将排序好的数组中的前k*m个pair元素放入到一个新的集合vector中,然后按照下标排序
  3. 输出前k-1组的最后一个下标(如下代码所示)

AC代码:

#include<bits/stdc++.h>
using namespace std;
using LL = long long;
int main(){
 //  ifstream cin("input.txt");
    int n, m, k;
    cin >> n >> m >> k;
    vector<pair<int, int> >v(n);
    for(int i = 0; i < n; i++){
        cin >> v[i].first;
        v[i].second = i;
    }
    sort(v.begin(), v.end(), [](pair<int, int>pa, pair<int, int>pb)->bool{
            if(pa.first != pb.first)
                return pa.first > pb.first;
            return pa.second < pb.second;
         });
    vector<pair<int, int> > v2;
    LL cnt = 0;
    for(int i = 0; i < k * m; i++){
        cnt += v[i].first;
        v2.emplace_back(v[i]);
    }
    sort(v2.begin(), v2.end(), [](pair<int, int>pa,pair<int, int>pb)->bool{
            return pa.second < pb.second;
         });
    cout << cnt << endl;

    for(int i = m-1, t = 1; t < k;t++, i += m){
        cout << v2[i].second+1 << " ";
    }
	return 0;
}

C. Trailing Loves (or L’oeufs?)

题目大意:

将n!转化成b进制后,尾部的0有多少个

解题思路(数论):

一个数转化成b进制后尾部的0的数目,就是这个数中 b k b^k bk中的k的个数。
那么我们可以将b分解成素数的乘积,即 b = p 1 a 1 ∗ p 2 a 2 ∗ . . . ∗ p k a k b = p_{1}^{a_1}*p_{2}^{a_2}*...*p_{k}^{a_k} b=p1a1p2a2...pkak,然后求出最小的b的分解中每个素数 p i p_i pi的n!对应的素数分解中的倍数。n!阶乘中 p i p_i pi的指数的个数为 n p i + n p i 2 + . . . + n p i r \frac{n}{p_i}+\frac{n}{{p_i}^2}+...+\frac{n}{{p_i}^r} pin+pi2n+...+pirn,其中 p i r &lt; = n {p_i}^r&lt;=n pir<=n。所以本题最终所求为: m i n ( n p i + n p i 2 + . . . + n p i r ) a i ) , 1 &lt; = i &lt; = k min(\frac{\frac{n}{p_i}+\frac{n}{{p_i}^2}+...+\frac{n}{{p_i}^r)}}{a_i}),1&lt;=i&lt;=k min(aipin+pi2n+...+pir)n),1<=i<=k

AC代码:

#include<bits/stdc++.h>
using namespace std;
using LL=unsigned long long ;
int main(){
    LL n,b;
    cin>>n>>b;
    map<LL, LL> M;
    LL i = 2;
    while(i <= b / i){//此处有坑,当心乘法LL溢出,所以用除法判断
        while(b % i == 0){
            M[i]++;
            b /= i;
        }
        i++;
    }
    if(b!=1)M[b]++;
    LL gmax = ~0LL;
    for(auto p: M){
        LL a = 1;
        LL cnt = 0;
        while(a <= n/p.first){//此处有坑,当心乘法LL溢出,所以用除法判断
            a *= p.first;
            cnt += n / a;
        }
        gmax = min(gmax, cnt / p.second);
    }
    cout << gmax << endl;
    return 0;
}

D. Flood Fill

题目大意:

一个长度为n的数组c,每个位置i都有一种颜色c[i],如果连续的一段区间颜色全部相同,则说明是同一块。每次变换一块的颜色算操作一次,求将整个数组变成仅有一种颜色需要操作多少次。

解题思路(动态规划):

设将区间[l, r]变为一种颜色c[l]的最少变换次数为dp[l][r][0],
设将区间[l, r]变为一种颜色c[r]的最少变换次数为dp[l][r][1],
那么则有动态转移方程为:

dp[l-1][r][0] = min(dp[l-1][r][0], dp[l][r][k] + (t != c[l-1]));// 当r > 0
dp[l][r+1][1] = min(dp[l][r+1][1], dp[l][r][k] + (t != c[r+1]));// 当r < n-1

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    //ifstream cin("input.txt");
    int n;
    cin >> n;
    vector<int>c(n);
    for(int i = 0; i < n; i++){
        cin >> c[i];
    }
    int dp[n][n][2];
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            if(i == j){
                dp[i][j][0] = dp[i][j][1] = 0;
            }else{
                dp[i][j][0] = dp[i][j][1] = INT_MAX/2;
            }
        }
    }
    for(int r = 0; r < n; r++){
        for(int l = r; l >= 0; l--){
            for(int k = 0; k < 2; k++){
                int t = (k?c[r]:c[l]);
                if(l)
                    dp[l-1][r][0] = min(dp[l-1][r][0], dp[l][r][k] + (t != c[l-1]));
                if(r < n-1)
                    dp[l][r+1][1] = min(dp[l][r+1][1], dp[l][r][k] + (t != c[r+1]));
            }
        }
    }
    cout << min(dp[0][n-1][0], dp[0][n-1][1]) << endl;
    return 0;
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值