美文网首页
Codeforces Round 570 (Div 3) 题解

Codeforces Round 570 (Div 3) 题解

作者: 叔丁基锂_ | 来源:发表于2019-06-27 22:07 被阅读0次

    通过题目:A-D (4/8)

    A Nearest Interesting Number

    题意:定义interesting number是一个数如果每一位之和是4的倍数,先给出一个数a (1≤𝑎≤1000),找出一个大于等于a的最小的interesting number

    思路:最开始的我wa了一发,因为我只考虑了a到a+4(我是傻逼)

    public static void main(String[] args) {
       Scanner scanner=new Scanner(System.in);
       int a=scanner.nextInt();
       for(int i=a;i<=1003;i++){
       if(cal(Integer.toString(i))==0){
           System.out.println(i);
           return;
           }
       }
    }
    
    static int cal(String str){
        int res=0;
        for(char ch:str.toCharArray()){
          res=res+(ch-'0');
          res%=4;
        }
        return res;
    }
    

    通过时间:7(+1)

    B Equalize Prices

    题解:你有n个货物,每个货物的价格可能不同,你想把他们的价格调成某个数,但是每个商品的调节范围为k,求这个数最大是多少

    思路:看最小值+k和最大值-k有没有交集即可,如果有的话,那就是最小值+k

    int main(){
        int round;
        scanf("%d", &round);
        while(round--){
            int n, k;
            scanf("%d%d", &n, &k);
            for (int i = 1; i <= n;i++){
                scanf("%d", &arr[i]);
            }
            sort(arr + 1, arr + 1 + n);
            if(arr[1]+k>=arr[n]-k){
                printf("%d\n", arr[1] + k);
            }
            else{
                puts("-1");
            }
        }
    }
    

    通过时间:18

    C Computer Game

    题意:你要用笔记本打游戏,笔记本初始电量为b,你有n轮游戏可以玩。每轮游戏可以直接玩消耗电a,或者边充电边玩消耗b(a严格大于b),问再能打完所有轮的前提下,最多不插电直接玩多少轮

    思路:wa了一发,因为该用long long的时候用了int,我是傻逼

    int main(){
        int round;
        scanf("%d", &round);
        while(round--){
            ll k, n, a, b;
            scanf("%lld%lld%lld%lld", &k, &n, &a, &b);
            ll r = k - n * b - 1;
            if (r < 0)
            {
                puts("-1");
                // continue;
            }
            else{
                printf("%lld\n", min(n,r / (a - b)));
            }
        }
    }
    

    通过时间:31(+1)

    D Candy Box (easy version)

    题意:给你n个糖的类型,你要给一些糖作为礼物,要求每种糖的数量应该是不同的,问这个礼物最多能有多少糖

    思路:先计数,然后排个序从大到小遍历,记录上一个选择的值,如果当前值大于上一个值,就把当前值改为上一个值-1

    int main(){
        int round;
        scanf("%d", &round);
        while(round--){
            int n;
            scanf("%d", &n);
            fill(arr, arr + 1 + n, 0);
    
            for (int i = 1; i <= n; i++)
            {
                int x;
                scanf("%d", &x);
                arr[x]++;
            }
            ll res = 0;
            sort(arr + 1, arr + 1 + n);
            int cur = maxn;
            for (int i = n; i >= 1 && arr[i]&&cur;i--){
                if(arr[i]<cur){
                    res += arr[i];
                }
                else{
                    arr[i] = cur - 1;
                    res += arr[i];
                }
                cur = arr[i];
            }
            printf("%lld\n", res);
        }
    }
    

    这个题目错了3发,前两发是想了个假算法,最后一发是由于memset 导致TLE

    通过时间:75(+3)

    E/H Subsequences

    题意:给一个n长的字符串,现要利用这个字符串的子序列填充一个容量为k的集合(集合元素不重复)(1≤𝑛≤100,1≤𝑘≤1012),每个子序列的代价是n-长度,求填充满的这个集合的最小代价

    思路:考虑dp,dp[i][j]表示前i个字符中长度为j的不同的字符串数量。用last数组记录第i个字符上一个出现的位置,于是得到状态转移方程如下:

    • 如果last[i]=0 ,也就是说这个位置的字符是整个字符串的第一次出现,这样分两种情况讨论:第i个字符出现与否。于是有dp[i][j]=dp[i-1][j]+dp[i-1][j-1]
    • 如果last[i]!=0,注意到last[i]-1 取j-1个字符的每个情况,都会和从i-1 取j-1个字符重复。因此在考虑第二种情况:即第i个字符出现时,需要额外减去dp[last[i]-1][j-1]。于是,dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] - dp[last[i]-1][j-1];

    注意这个状态转移方程是指数的,所以最后很显然会溢出。主要到如果dp[i][j]>k , 大于k的部分并没有什么意义,直接赋值为k即可

    for (int i = 0; i <= n;i++){
        dp[i][0] = 1;
    }
    for (int i = 1; i <= n; i++)
    {
        dp[i][i] = 1;
        for (int j = 1; j < i; j++)
        {
          if (last[i] == 0){
               dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
          }
          else
                dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] - dp[last[i]-1][j-1];
          if(dp[i][j]>k)
                dp[i][j] = k;
        }
    }
    

    通过时间:♾

    F Topforces Strikes Back

    题意:从n个数选至多三个数,要求这些数字互相不整除。对这几个数求和,求这个和的最大值。

    思路:虽然数字数量可能很多,但是实际上一个2e5以内的数,最多只有160个因数(166320和196560)。分两种情况处理:

    • 取小于等于两个数:最大的数必须取,否则只能取这个最大的值的一个因数,其中最大的是m/2,这样两个数加起来都不会更优于只取一个数
    • 取三个数:要么取最大的数然后搭上两个别的数(回到上一种情况),要么取(如果最大的数是m) m/2, m/3, m/5:因为不包含最大数,说明必然是m的三个因数,否则可以带上最大数达到更大的和。

    这样,对这些数字去重然后排序只有就很轻易得到结果了

    #include <bits/stdc++.h>
    using namespace std;
    set<int,greater<int>> se;
    
    bool test235(int top){
        if(top%30)
            return false;
        return se.count(top / 2) && se.count(top / 3) && se.count(top / 5);
    }
    
    int solve_two(){
        if(se.begin()==se.end()){
            return 0;
        }
        int top = *se.begin();
        int ans = top;
        se.erase(se.begin());
        
        for (auto val : se)
        {
            if (top % val)
            {
                ans += val;
                break;
            }
        }
        return ans;
    }
    
    int main(){
        int round;
        scanf("%d", &round);
        while(round--){
            int n;
            scanf("%d", &n);
            se.clear();
            for (int i = 1; i <= n; i++)
            {
                int x;
                scanf("%d", &x);
                se.insert(x);
            }
            int top = *se.begin();
            int ans = solve_two();
            if (test235(top))
            {
                ans = max(ans, top / 2 + top / 3 + top / 5);
            }
            for(int i=1;i*i<=top;i++){
                if(top%i==0){
                    se.erase(i);
                    se.erase(top/i);
                }
            }
            ans = max(ans, solve_two() + top);
            printf("%d\n", ans);
        }
    }
    

    通过时间:♾

    G Candy Box (hard version)

    题意:与D相比,对于每颗糖多了一个参数f,如果f为1表示你不喜欢这颗糖,如果f为0则代表你喜欢这颗糖。求在D的约束下(送的糖数量最多)的前提下尽可能送出不喜欢的糖,输出总数量和不喜欢的糖的数量

    思路:对于两个种类,如果能送出的糖果数量一样,那么优先选择不喜欢数量更多的那个

    #include <bits/stdc++.h>
    using namespace std;
    using ll = unsigned long long;
    const int maxn = 2e5 + 10;
    int arr[maxn];
    int fav[maxn];
    priority_queue<pair<int, int>> pq;
    
    int main(){
        int round;
        scanf("%d", &round);
        while(round--){
            int n;
            scanf("%d", &n);
            fill(arr + 1, arr + 1 + n, 0);
            fill(fav + 1, fav + 1 + n, 0);
            for (int i = 1; i <= n; i++)
            {
                int x, y;
                scanf("%d%d", &x, &y);
                arr[x]++;
                fav[x] += y;
            }
            while(!pq.empty()){
                pq.pop();
            }
            for (int i = 1; i <= n;i++){
                if(arr[i]){
                    pq.emplace(arr[i], fav[i]);
                }
            }
            int cur = maxn;
            ll sz = 0, tot = 0;
            while (!pq.empty()&&cur>0)
            {
                auto top = pq.top();
                pq.pop();
                if(top.first<cur){
                    sz += top.first;
                    tot += top.second;
                    cur = top.first;
                }
                else{
                    top.first = cur - 1;
                    top.second = min(top.second, top.first);
                    pq.push(top);
                }
            }
            printf("%llu %llu\n", sz, tot);
        }
    }
    
    

    Reference

    相关文章

      网友评论

          本文标题:Codeforces Round 570 (Div 3) 题解

          本文链接:https://www.haomeiwen.com/subject/zwidcctx.html