zoukankan      html  css  js  c++  java
  • “科大讯飞杯”第18届上海大学程序设计联赛春季赛暨高校网络友谊赛

    Contest Info


    Practice Link

    SolvedABCDEFGHIJKL
    6/12 O O O  O  O     Ø        
    • O 在比赛中通过 
    • Ø 赛后通过
    • ! 尝试了但是失败了
    • - 没有尝试

    Solutions


    H.纸牌游戏

    题意:

    每组给你一个字符串$S$和一个数字$k$

    要求用$S$中的字符拼出一个长度为$k$的能被$3$整除的非负整数,不能有前导$0$.

    如果无解输出$-1$,否则输出最大的答案.

    思路:

    我的思考方向错了直接导致实现起来很复杂,于时理所当然花了很多时间还没做出来

    可以合理地想到从高到低依次枚举每一位的数,然后判断一下后面是否存在方案,问题在于如何快速判断

    设还还剩下的$mod 3=0,1,2$的数个数分别为$c[0dots 2]$

    设总共还需要$n$个,需要凑出$mod 3=t$的方案

    这时后我们假设枚举某一个,比如我们枚举$0$选了$i$个,设还剩下$n-i$个要选,设剩下两个选了$x,y$个,则有限制条件

    $$x+y=n-i,2x+y = t(mod 3)$$

    把$x$消掉,得到

    $$2n-2i-2y+y=t (mod 3)->y=2n−2i−t(mod3)$$

    我们可以根据各种限制条件解出$y$的可行区间,然后判断区间内是否存在一个$y$即可

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn = 1e5+100;
    int T, n, m, cnt[10], cntmod[3];
    char s[maxn];
    bool judge(int x, int m){
        if(!m) return !x;
        int a = cntmod[0], b = cntmod[1], c = cntmod[2];
        int l0 = max(0, m-b-c), r0 = min(a, m);
        for(int i = l0; i <= r0; i++){
            int t = ((2*(m-i)-x)%3+3)%3;
            int l1 = max(0, m-i-c), r1 = min(b, m-i);
            while(l1%3!=t) l1++;
            if(l1<=r1) return true;
        }
        return false;
    }
    int main(){
        scanf("%d", &T);
        while(T--){
            scanf("%s%d", s+1, &m);
            for(int i = 0; i < 3; i++) cntmod[i] = 0;
            for(int i = 0; i <= 9; i++) cnt[i] = 0;
            int len = strlen(s+1);
            for(int i = 1;i<=len;i++){
                cnt[s[i] - '0']++;
                cntmod[(s[i] - '0') % 3]++;
            }
            for(int i = 9, j = n = 0; i >= 0; i--){
                while(cnt[i]&&n<m){
                    int k = (i+j)%3;
                    cnt[i]--, cntmod[i%3]--;
                    if(!judge((3-k)%3, m-n-1)){
                        cnt[i]++, cntmod[i%3]++;
                        break;
                    }
                    s[++n] = '0'+i, j = k;
                }
            }
            s[n+1] = '';
            if(n<m||(s[1]=='0'&&n>1)) printf("-1
    ");
            else printf("%s
    ", s+1);
        }
        return 0;
    }
    View Code

    之后重写得过程中,有两个问题需要注意:

    1.涉及到取模运算需要特别注意小细节

    2.strlen写在for循环里面会超时,正确做法是判断s[i]!=''或者单独开个变量保存strlen(s),这个超时的bug我找了一个小时


    Refrence:

    https://blog.nowcoder.net/n/4e41667992994b038e899f511c80882a

    https://ac.nowcoder.com/acm/contest/view-submission?submissionId=43525613

  • 相关阅读:
    15个新鲜出炉的 Photoshop 文本效果教程
    10个美丽的例子,插图在网页设计中的应用
    分享8个非常时髦的翻页特效(附代码片段)
    【Vue课堂】Vue.js 父子组件之间通信的十种方式
    Tippy.js – 轻量的 Javascript Tooltip 工具库
    12个美丽的网站与受到日出启发的配色方案
    精选:3个可以下载免费的高质量照片的网站
    nativefier
    Mark Text
    Puppeteer
  • 原文地址:https://www.cnblogs.com/wizarderror/p/12739066.html
Copyright © 2011-2022 走看看