牛客多校第六场记录

A

  • 题意: 垃圾分类
  • 思路: 模拟
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define ll long long
#define FOR(i,l,r) for(int i = l ; i <= r ;++i )
#define inf 1<<30
#define EPS (1e-9)
#define ALL(T)  T.begin(),T.end()
#define lson(i)     i<<1
#define rson(i)     (i<<1|1)
using namespace std;
typedef pair<int,int> pii;

int cnt[10];
char buf[3010];
char ma[1010];
int main(){
    int t;
    cin >> t;
    FOR(cas,1,t){
        scanf("%s%s",buf,ma);
        cnt[1] = cnt[2] = cnt[3] = 0;
        int len = strlen(buf);
        for(int i=0;i<len;++i){
            switch (ma[buf[i]-'a'])
            {
            case 'h':
                cnt[1]++;
                break;
            case 'w':
                cnt[2]++;
                break;
            case 'd':
                cnt[3]++;
                break;
            default:
                break;
            }
        }
        printf("Case #%d: ",cas);
        if(cnt[1]>=(len/4.0)){
            printf("Harmful\n");
        }else if(cnt[1]<=(len/10.0)){
            printf("Recyclable\n");
        }else if(cnt[3]>=cnt[2]*2){
            printf("Dry\n");
        }else{
            printf("Wet\n");
        }
    }
    return 0;
}

除数要double不然会wa QAQ

B

  • 题意: 将2进制的ipv6地址转换成最短的字典序最小的标准格式(需要缩0)
  • 思路: 模拟,先转成16进制,再去掉前置0,最后遍历所有缩0情况,获得答案.
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define ll long long
#define FOR(i,l,r) for(int i = l ; i <= r ;++i )
#define inf 1<<30
#define EPS (1e-9)
#define ALL(T)  T.begin(),T.end()
#define lson(i)     i<<1
#define rson(i)     (i<<1|1)
using namespace std;
typedef pair<int,int> pii;
 
char buf[1029];
char ox[110];
char ox2[110];
char ansStr[110];
void toOx(){    // 变成16进制
    int idx = 0;
    int val = 0;
    int oidx = 0;
    while(idx<128){
        val= (val<<1)+(buf[idx++]-'0');
        val= (val<<1)+(buf[idx++]-'0');
        val= (val<<1)+(buf[idx++]-'0');
        val= (val<<1)+(buf[idx++]-'0');
        if(val<10){
            ox[oidx] = val+'0';
        }else{
            ox[oidx] = val-10+'a';
        }
        oidx++;
        val = 0;
    }
    ox[oidx] = 0;
    oidx = 0;
    FOR(i,0,31){
        ox2[oidx++] = ox[i];
    }
    ox2[oidx] = 0;
    idx = oidx;
    oidx = 0;
    FOR(i,0,idx-1){
        if(ox2[i]=='0'){
            if(ox2[i+1]=='0'){
                if(ox2[i+2]=='0'){
                    ox[oidx++] = ox2[i+3];
                    ox[oidx++] = ':';
                    i+=3;
                }else{
                    ox[oidx++] = ox2[i+2];
                    ox[oidx++] = ox2[i+3];
                    ox[oidx++] = ':';
                    i+=3;
                }
            }else{
                ox[oidx++] = ox2[i+1];
                ox[oidx++] = ox2[i+2];
                ox[oidx++] = ox2[i+3];
                ox[oidx++] = ':';
                i+=3;
            }
        }else{
            ox[oidx++] = ox2[i];
            ox[oidx++] = ox2[i+1];
            ox[oidx++] = ox2[i+2];
            ox[oidx++] = ox2[i+3];
            ox[oidx++] = ':';
            i+=3;
        }
    }
    ox[oidx-1] = 0;
    // printf("%s\n%s\n",ox2,ox);
}
int cmp(string s1,string s2){
    if(s1.length() == s2.length()){
        return s1<s2;
    }
    return s1.length() <s2.length();
}
vector<string> as;
void ya0(){ // 压缩0
    vector<pii > pos;
    int len = strlen(ox);
    pii lin;
    FOR(i,0,len-1){
        if(ox[i]=='0'&&ox[i+1]==':'&&(i-1<0 ||ox[i-1]==':')){
            lin.second = i;
            lin.first = 0;
            while(i+2<len&&ox[i+2]=='0'){
                i+=2;
                lin.first++;
            }
            pos.push_back(lin);
        }
    }
    int idx= 0;
    sort(ALL(pos));
    if(pos.size()==0 || pos[pos.size()-1].first==0){
        FOR(i,0,len){
            ansStr[i] = ox[i];
        }
        as.push_back(ansStr);
        return ;
    }
    int tmp = pos[pos.size()-1].first;
    for(auto lin:pos){
        if(lin.first!=tmp)  continue;
        idx = 0;
        FOR(i,0,len-1){
            if(i!=lin.second){
                ansStr[idx++] = ox[i];
            }else{
                if(ansStr[idx-1]!=':')
                    ansStr[idx++] = ':';
                ansStr[idx++] = ':';
                i += lin.first*2+1;
            }
        }
        ansStr[idx] = 0;
        // string tstr = ansStr;
        as.push_back(ansStr);
    }
    sort(ALL(as),cmp);
}
int main(){
    int t;
    scanf("%d",&t);
    FOR(cas,1,t){
        as.clear();
        scanf("%s",buf);
        toOx();
        ya0();
        printf("Case #%d: ",cas);
        cout << as[0] << '\n';
    }
    return 0;
}

压中间的零和压首尾的零,字符串长度不一样. 直接遍历所有情况sort一遍即可

D

  • 题意: 有k个箱子,n个物品,每个物品有一个体积\(a_i\). 对于每个箱子都要放到不能再放物品为止再去下一个箱子放.求最小的能放下所有物品的箱子容量
  • 思路: 从下界\(\frac{\sum{a_i}}{n}\)开始枚举箱子的大小,multiset的upper_bound(第一个大于的)来模拟放的过程
#include<bits/stdc++.h>
#define ll long long
#define FOR(i,l,r) for(int i = l ; i <= r ;++i )
#define inf 1<<30
#define EPS (1e-9)
#define ALL(T)  T.begin(),T.end()
#define lson(i)     i<<1
#define rson(i)     (i<<1|1)
using namespace std;
const int maxn(1e4+5);
int a[maxn],r,l;
int n,k;
void input(){
    memset(a,0,sizeof(a));
    scanf("%d%d",&n,&k);
    r = 0;
    FOR(i,1,n){
        scanf("%d",&l);
        r += l;
        a[l]++;
    }
    r/=k;
}
multiset<int> s;
int check(int mid){
    s.clear();
    for(int i=1;i<=1000;++i){
        for(int j=1;j<=a[i];++j){
            s.insert(i);
        }
    }
    for(int i=1;i<=k;++i){
        int y = mid;
        while(y){
            auto iter = s.upper_bound(y);
            if(iter != s.begin()){
                --iter;
                y -=(*iter);
                s.erase(iter);
            }else{
                break;
            }
        }
    }
    return s.size()==0;
}

int main(){
    int t;
    scanf("%d",&t);
FOR(cas,1,t){
    input();
    while(!check(r)){
        r++;
    }
    printf("Case #%d: %d\n",cas,r);
}
    return 0;
}

这道题很容易想到二分,从而想到\(O(n^2)\)\(check()\)+\(O(log(T))\)的二分,但这种取值不连续的填满问题是不满足二分的性质的... 可以通过每次枚举一段区间来二分.
有一道非常相似的题目U33405 纽约

G

  • 题意: 给出n个字母\(A到J\)的字符串,求是否有一个\(0到9\)的排列能将所有字符串映射为一个合法的日期且为星期五.
  • 思路: 先预处理出所有的排列,然后枚举通过蔡勒公式判断是否合法
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define ll long long
#define FOR(i,l,r) for(int i = l ; i <= r ;++i )
#define inf 1<<30
#define EPS (1e-9)
#define ALL(T)  T.begin(),T.end()
#define lson(i)     i<<1
#define rson(i)     (i<<1|1)
using namespace std;
typedef pair<int,int> pii;
  
const int maxn = 1e6+10;
int mon[15] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int whatDay(int d,int m,int y){
    int ans;
    if(m==1||m==2)
        m+=12,y--;
    ans = (d+2*m+3*(m+1)/5 + y + y/4 - y/100 + y/400 + 1)%7;
    return ans == 5;
}
 
int check(string op,int* a){
    int y = a[op[0]-'A']*1000 + a[op[1]-'A']*100 + a[op[2]-'A']*10 + a[op[3]-'A'];
    int m = a[op[5]-'A']*10 + a[op[6]-'A'];
    int d = a[op[8]-'A']*10 + a[op[9]-'A'];
    if(y%4==0 && y%100 || y%400==0) mon[2] = 29;
    else mon[2] = 28;
    if(y < 1600 || y>9999 || m<1 || m>12 || d<1 || d>mon[m])  return 0;
    return whatDay(d,m,y);
}
 
int p[3628800][10];
 
void init(){
    int a[10];
    for(int i=0;i<10;++i)
        a[i] = i;
    int cnt = 0;
    do{
        memcpy(p[cnt++],a,sizeof(a));
    }while(next_permutation(a,a+10));
     
}
string buf[maxn];
vector<int> tr;
int main(){
    int t,n;
    init();
    cin >> t;
FOR(cas,1,t){
    cin >> n;
    FOR(i,1,n){
        cin >> buf[i];
    }
    sort(buf+1,buf+n);
    n = unique(buf+1,buf+n+1)-buf-1;
    random_shuffle(buf+1,buf+n+1);
    printf("Case #%d: ",cas);
    int ok = 0;
    FOR(i,0,3628800-1){
        ok = 1;
        FOR(j,1,n){
            if(!check(buf[j],p[i])){
                ok = 0;
                break;
            }
        }
        if(ok){
            // tr.push_back(i);
            FOR(j,0,9){
                printf("%d",p[i][j]);
            }
            break;
        }
    }
    if(!ok){
        printf("Impossible");
    }printf("\n");
}
 
    return 0;
}

J

  • 题意: 给出n*m的矩阵,每列的元素要从后往前选,每行全选会得到一个奖励,求能获得的最大收益.
  • 思路: 枚举j列为所选最短的列(获得奖励),再枚举每一行的最大收益(从当前选到最后)

#include<bits/stdc++.h>
#define ll long long
#define FOR(i,l,r) for(int i = l ; i <= r ;++i )
#define inf 1<<30
#define EPS (1e-9)
#define ALL(T)  T.begin(),T.end()
#define lson(i)     i<<1
#define rson(i)     (i<<1|1)
using namespace std;
typedef pair<int,int> pii;
const int maxn = 1e4+10;
  
ll c[maxn][maxn],d[maxn],mx[maxn][maxn],smx[maxn];
int n,m;
  
int main(){
    int t;
    scanf("%d",&t);
    FOR(cas,1,t){
        scanf("%d%d",&n,&m);
        int x;
        FOR(i,1,n){
            FOR(j,1,m){
                scanf("%d",&x);
                c[i][j]=c[i][j-1]-x;
            }
            mx[i][m+1] = -1ll<<60;
            for(int j=m;j>=0;--j){
                mx[i][j] = max(mx[i][j+1],c[i][j]);
            }
        }
        FOR(j,0,m){
            smx[j] = 0;
            FOR(i,1,n){
                smx[j] += mx[i][j];
            }
        }
        ll ans = 0,D=0,sum;
        for(int j=0;j<=m;++j){
            if(j) scanf("%d",&x),D+=x;
            sum = -1ll<<60;
            for(int i=1;i<=n;++i){
                // if(c[i][j]-mx[i][j] > sum){
                //     sum = c[i][j] - mx[i][j];
                // }
                sum = c[i][j] - mx[i][j] + smx[j];
                ans = max(ans,sum+D);
            }
            // sum+= smx[j];
            // for(int i=1;i<=n;++i) sum+= mx[i][j];
            // ans = max(ans,sum+D);
        }
        printf("Case #%d: %lld\n",cas,ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xxrlz/p/11317414.html