2019牛客暑期多校训练营(第六场)

 // 比赛链接:https://ac.nowcoder.com/acm/contest/886#question

 // 又是自闭的一下午,今天我爆零了T_T

 // 开始直奔B题,一看感觉很容易,进制转换然后处理一下输出就完事了,签到题吧

 // 喝完药就开始码,队友说A题签到,然后A了。我继续,看榜感觉不太对劲,B通过率真低。

 // 写着突然B题更新,没问题,描述更清晰了而已,没有曲解题意,继续写。调好了样例,直接交。

 // WA1 。。。WA2。。。 WA3。。。甩锅不写了

 // 吴先生在写D题写半天了,我瞅一眼不就二分,我也写好了,互相交全WA。

 // 吴先生一看输出都写错了,没敢交了。我自闭。

 // 剩下时间看了G,想到那个求星期的公式,然后构思怎么枚举,断断续续写了快一个小时。

 // 脑子有点不清晰,不知道用循环写还是dfs搜,反反复复,又觉得复杂度太高,怎么都要T。

 // 陷入B-D-G死循环。
View Code

 

A - Garbage Classification

题意:给了一堆垃圾,判断它是有害垃圾/可回收垃圾/干垃圾/湿垃圾。两行输入,一行字符串表示垃圾,另一行代表每个小写字母的垃圾种类。

题解:模拟。真正的签到题。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char s[3010],t[30];
int main()
{
    int T,cas=0;cin>>T;
    while(T--)
    {
        printf("Case #%d: ",++cas);
        cin>>s>>t;
        int h=0,d=0,w=0;
        int ls = strlen(s);
        for(int i=0;i<ls;++i)
        {
            if(t[s[i]-'a']=='h')
                h++;
            else if(t[s[i]-'a']=='d')
                d++;
            else if(t[s[i]-'a']=='w')
                w++;
        }

        if(4*h>=ls)
            puts("Harmful");
        else if(h*10<=ls)
            puts("Recyclable");
        else if(d>=2*w)
            puts("Dry");
        else
            puts("Wet");
             
    }
    return 0;
}
View Code

B - Shorten IPv6 Address  (补)

题意:给一段ipv6的二进制地址,让你转成16进制输出,如果有至少两段的连续0,可以省写为两个冒号::,但只能用一次。求缩写最短的形式中字典序最小的答案。

思路:字典序最小,首先保证串最短,那么找到连续0最长的部分改写为【::】的即可,长度相等选择靠后的。

坑:首尾位置与中间位置加上【::】的长度不相同。。。

题解:官方题解不知道在说什么,看了直播也没听懂在讲什么,有一条弹幕给了一个【将最长的靠后0串改为::】的反例,我百思不得其解,正准备让电脑跑一下他们的字典序大小,写一起才看明白了:

【::】放在开头或结尾长度会比放中间多一位!!!

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
  
char s[130];
int v[10];
int z[10];
int main() {
    int T; cin>>T; int t = 0;
    while(t<T) {
        scanf("%s", s+1);
        memset(z, 0, sizeof(z));
         
        printf("Case #%d: ", ++t);
        int value = 0;
        for(int i=1;s[i];i++) {
            value = value*2 + (s[i]=='1');
            if(i%16==0) {
                v[i/16] = value;
                value = 0;
            }
        }
          
         
        for(int i=8;i>=1;i--) {
            if(v[i]==0) {
                z[i] = z[i+1] + 1;
                z[i+1] = 0;
            }
            else
                z[i] = 0;
        }
        if(z[1]==8) {
            printf("::
");
            continue;
        }
          
        int len = 0, cnt = 0;
        int maxLen = -1, pos = -1;
         
        for(int i=1;i<=8;i++) {
            if(v[i]==0) {
                ++len;
            } else {
                if(len>=2) {
                    ++cnt;
                    if(maxLen<=len) {
                        maxLen = len;
                        pos = i-1;
                    }
                }
                len = 0;
            }
            if(i==8 && len>=2) {
                ++cnt;
                if(maxLen<len || maxLen==len && maxLen==z[1] && cnt<=2) {
                    maxLen = len;
                    pos = i;
                }
            }
        }
        if(cnt<1) {
            for(int i=1;i<=8;i++) {
                printf("%0x%c", v[i], i==8?'
':':');
            }
        } else
            {
            int k = pos;
            while(v[k]==0 && k>=1) k--;
            if(k==0) printf(":");
            for(int i=1;i<=k;i++) {
                printf("%0x:", v[i]);
            }
            printf(":");
  
            if(pos==8) {
                printf("
");
                continue;
            }
            for(int i=pos+1;i<=8;i++)
                printf("%0x%c", v[i], i==8?'
':':');
        }
          
    }
      
    return 0;
}
View Code

D - Move(补)

题意:有n个物品,每个体积vi,给你k个相同容积的箱子装,装箱按照从大到小顺序直到塞满或装不下为止。问箱子的最小容积。

思路:不能二分。。。因为箱子容积和k之间不满足单调性(即使经验上一致,也没找到反例)

官方反例:

n = 15  k = 5

39 39 39 39 39 60 60 60 60 60 100 100 100 100 100

199为合法的答案,但200不是,201也不是。

AC代码:(把二分改成暴力从 max(totV/k, maxV)开始枚举就够了。。)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
   
int v[1010], n, k;
bool vis[1010];
bool ok(int V) {
    int res = 0, cnt = 0;
    int now = V;
    memset(vis, 0, sizeof(vis));
    while(cnt<n) {
        for(int i=n;i>=1&&now;i--)
            if(!vis[i] && now>=v[i]) {
                now -= v[i];
                vis[i] = 1;
                ++cnt;
            }
        res++;
        now = V;
    }
    return res<=k;
       
}
   
int main() {
    int T; cin>>T; int t = 0;
    while(t<T) {
        scanf("%d %d", &n, &k);
        int totV = 0, maxV = 0;
        for(int i=1;i<=n;i++) {
            scanf("%d", &v[i]);
            totV += v[i];
            maxV = max(maxV, v[i]);
        }
        sort(v+1, v+1+n);
           
        int ans = max(maxV, (totV+k-1)/k);
        while(!ok(ans)) {
            ++ans;
        }
         
        printf("Case #%d: %d
", ++t, ans);
    }
       
    return 0;
}
View Code

G - Is Today Friday?(补)

题意:给你n个只包含A~J大写字母的yyyy/mm/dd形式的加密字符串,求解A~J使日期都是星期五。(n<=10000)

思路:每个日期枚举的规模在:2(月开头数字) * 4(日开头数字)  * 8 * 7 * 6 * 5 * 4 * 3 =  1.6e5,然后再判断n个是否满足。

题目数据sb。。。知道蔡勒公式再暴力枚举就完事了。。。关键在于去重。。。

sort(date+1, date+1+n); 
n = unique(date+1, date+1+n) - (date+1);

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
 
struct node {
    char y[5];
    char m[3];
    char d[3];
    string s;
    bool operator<(const node& a) {
        return s < a.s;
    }
    bool operator==(const node& a) {
        return s == a.s;
    }
}date[100100];
 
int n;
 
bool valid(int y, int m, int d) {
    if(m>12 || d>31) return false;
    if(m==2) {
        if(d<=28) return true;
        else if(d>29) return false;
        return y%400==0 || (y%4==0 && y%100!=0);
    }
    if(d==31) {
        switch(m) {
//            case 1: case 3: case 5: case 7: case 8:
//            case 10: case 12: return true;
            case 4: case 6: case 9: case 11: return false;
            return true;
        }
    }
    return true;
}
bool check(int y, int m, int d) { // 蔡勒公式 w为星期,0表示星期天
    if(m==1 || m==2) m += 12, --y;
     
    int c = y / 100;
    y = y - c * 100;
    int w = y + y / 4 + c / 4 - 2 * c + 26 * (m + 1) / 10 + d - 1;
    w = (w%7+7)%7;
    return w==5;
}
 
bool vis[10], flag;
int dic[10];
int month_First[10];
int day_First[10];
 
void dfs(int k) {
    if(k>9) {
        for(int i=1;i<=n;i++) {
            int year = dic[date[i].y[0]-'A']*1000 + dic[date[i].y[1]-'A']*100 +
                dic[date[i].y[2]-'A']*10 + dic[date[i].y[3]-'A'];
            if(year<1600) return;
             
            int mon = dic[date[i].m[0]-'A']*10 + dic[date[i].m[1]-'A'];
            int day = dic[date[i].d[0]-'A']*10 + dic[date[i].d[1]-'A'];
            if(!valid(year, mon, day) || !check(year, mon, day)) return;
        }
        flag = true;
        for(int i=0;i<=9;i++) {
            printf("%d", dic[i]);
        }
        printf("
");
        return;
    }
     
    for(int i=0;i<=9;i++) {
        if(i>2 && month_First[k]) break;
        if(i>3 && day_First[k]) break;
         
        if(!vis[i]) {
            dic[k] = i;
            vis[i] = 1;
             
            if(!flag)
                dfs(k+1);
             
            vis[i] = 0;
            dic[k] = -1;
        }
    }
}
 
 
 
int main() {
    int T; cin>>T; int t=0;
    while(t<T) {
        scanf("%d", &n);
        memset(month_First, 0, sizeof(month_First));
        memset(day_First, 0, sizeof(day_First));
         
        for(int i=1;i<=n;i++) {
            scanf("%4s/%2s/%2s", date[i].y, date[i].m, date[i].d);
            date[i].s =  date[i].y;
            date[i].s += date[i].m;
            date[i].s += date[i].d;
             
            month_First[date[i].m[0]-'A'] = 1;
            day_First[date[i].d[0]-'A'] = 1;
        }
         
        sort(date+1, date+1+n);
        n = unique(date+1, date+1+n) - (date+1);
 
        printf("Case #%d: ", ++t);
        flag = 0;
        dfs(0); 
 
      if(!flag) printf("Impossible
");
         
    }
     
    return 0;
}
View Code

J - Upgrading Technology


    (未完待补。。。) 

原文地址:https://www.cnblogs.com/izcat/p/11296827.html