ZJCPC2020 第17届 浙江省赛The 17th Zhejiang Provincial Collegiate Programming Contest(ABCIK 5题)

Posted 小哈里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZJCPC2020 第17届 浙江省赛The 17th Zhejiang Provincial Collegiate Programming Contest(ABCIK 5题)相关的知识,希望对你有一定的参考价值。

补题地址:https://codeforces.com/gym/102770
本文按照通过率补的题

K. Killing the Brute-force

  • 题意:给定两个数组,分别是标准程序和用户程序的运行时间,当后者大于前者的 3倍,则不能通过此题。求出最小的使得用户不能通过的题号(从 1 开始编号),否则输出-1
  • 思路:把输入存起来扫一遍即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1100;
int a[maxn], b[maxn];

int main()
    int T;  cin>>T;
    while(T--)
        int n;  cin>>n;
        for(int i = 1; i <= n; i++)cin>>a[i];
        for(int i = 1; i <= n; i++)cin>>b[i];
        int t = -1;
        for(int i = 1; i <= n; i++)
            if(b[i]>a[i]*3)
                t = i; break;
            
        
        cout<<t<<"\\n";
    
    return 0;



A. AD 2020

  • 题意:给你起始日期和终止日期,问你其中有多少个日期构成的字符串中包含202。
  • 思路:因为多组数据,考虑前缀和预处理出2000到9999的所有日期个数,对于输入直接输出,也可以把所有满足条件的数都存到数组, 每次二分两个边界相减输出即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e6+10;
#define ios ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
int days[] =  0,31,28,31,30,31,30,31,31,30,31,30,31 ;
int a[maxn], cnt;

int main()
    IOS;
    for(int i = 2000; i <= 9999; i++)
        if(i%4==0&&i%100!=0 || (i%400==0))days[2] = 29;
        else days[2] = 28;
        for(int j = 1; j <= 12; j++)    
            for(int k = 1; k <= days[j]; k++)
                int x = i*10000+j*100+k;
                string s = to_string(x);
                if(s.find("202") != s.npos)
                    a[++cnt] = x;
                
            
        
    
    int T;  cin>>T;
    while(T--)
        int y1,m1,d1,y2,m2,d2;  cin>>y1>>m1>>d1>>y2>>m2>>d2;
        int x = y1*10000+m1*100+d1, y = y2*10000+m2*100+d2;
        int p1 = lower_bound(a+1,a+cnt+1, x)-a;
        int p2 = upper_bound(a+1,a+cnt+1, y)-a;
        cout<<p2-p1<<"\\n";
    
    return 0;

I. Invoking the Magic

  • 题意:现有n双袜子,但是被混合起来了,即一组袜子中可能是两只不同的袜子。宝宝有魔法能够将k组袜子重新匹配,使得这k组袜子中相同的袜子分到一起。要求是这k组中的袜子必须能够匹配,不能出现单只独一无二的袜子。求能够将所有袜子重新匹配的最小k
  • 思路:
    只有1e5双袜子,但是袜子的编号却是叛逆的2^30,所以需要离散化一下,可以用unordered_map对节点重新编号。
    对于分组令k最小,等价于寻找最大的联通块的点数(最坏的结果就是k == n,n组袜子丢进去也能匹配),可以直接并查集维护一下即可。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
typedef long long LL;

int ans;
//the map with unionfindset
unordered_map<int, int>fa, siz;
int find(int x) return x==fa[x]?x:fa[x]=find(fa[x]); 
int merge(int x, int y)
    x = find(x), y = find(y);
    if(x != y)
        fa[x] = y;
        siz[y] += siz[x];
        ans = max(ans, siz[y]);
        return 1;
    
    return 0;


int main()
    IOS;
    int T;  cin>>T;
    while(T--)
        fa.clear();  siz.clear();  ans = 0;
        int n;  cin>>n;
        for(int i = 1; i <= n; i++)
            int a, b;  cin>>a>>b;
            if(!fa.count(a))fa[a]=a, siz[a] =1;//新建节点
            if(!fa.count(b))fa[b]=b, siz[b] =1;
            merge(a,b);
        
        cout<<ans<<"\\n";
    
    return 0;



B. Bin Packing Problem

  • 题意:给你n个物品和它们的体积,还有容量为C的集装箱,要求按它给你的顺序放在集装箱里。现有两种方案。
    第1种:每次在现有的集装箱里从左到右扫一遍,放到第一个能放进去的集装箱里,如果没有则在最右边加一个集装箱放。
    第2种:每次在现有的集装箱里选择剩余容量最接近当前物品的集装箱,如果没有则在最右边加一个集装箱放。
    输出两种方案下使用集装箱的数量

  • 思路:
    对于两种方案来说,遍历肯定会超时。
    对于方案1:用线段树维护区间最大值,每次优先去左子树,相当于分治的思想。
    对于方案2:我们可以在multiset里二分,每次快速的找到剩余容量最接近当前物品的的集装箱去放。

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
typedef long long LL;
const int maxn = 1e6+10;

int a[maxn];
multiset<int>st;

//线段树
struct SegmentTree
    typedef long long LL;
    #define maxn 1000010
    #define lch p<<1
    #define rch p<<1|1
    int tr[maxn<<2];
    int ans = 0;
    void up(int p) tr[p] = max(tr[lch], tr[rch]); 
    void build(int p, int l, int r, int C)//初始n个集装箱都剩余C
        tr[p] = C;
        if(l == r)return ;
        int mid = l+r>>1;
        build(lch, l, mid, C);
        build(rch, mid+1, r, C);
    
    void add(int p, int l, int r, int v, int C)//选个靠左的集装箱里放入v
        if(l == r)
            if(tr[p]==C)ans++; //多用一个箱子
            tr[p] -= v;
            return ;
        
        int mid = l+r>>1;
        if(tr[lch] >= v)add(lch, l, mid, v, C);//左边最大的>=v,尽可能靠左
        else add(rch, mid+1,r,v, C);
        up(p);
    
sgt;

int main()
    IOS;
    int T;  cin>>T;
    while(T--)
        int n, C;  cin>>n>>C;
        for(int i = 1; i <= n; i++)cin>>a[i];
        sgt.ans = 0;
        sgt.build(1,1,n, C); //最多用n个箱子
        for(int i = 1; i <= n; i++)//一个一个放进去
            sgt.add(1,1,n,a[i], C);
        cout<<sgt.ans<<" ";
        st.clear();//维护所有箱子的剩余容量
        st.insert(C-a[1]);
        for(int i = 2; i <= n; i++)
            auto p = st.lower_bound(a[i]);//刚好能装下的
            if(p == st.end())//不存在
                st.insert(C-a[i]);//加一个
                continue;
            else
                int v = *p-a[i];
                st.erase(p);
                st.insert(v);
            
        
        cout<<st.size()<<"\\n";
    
    return 0;



C. Crossword Validation

  • 题意:给出一个n*n的矩阵,问矩阵中所有单词的权值和。
  • 思路:用字典树来记录m个单词以及它们的权值,之后遍历矩阵查找。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
const int maxn = 4e6+10;

struct Tire
    struct node 
        int ch[30], v, cnt; 
        void init()
            memset(ch,-1,sizeof ch);
            v = cnt = 0;
        
    tr[maxn];
    int root, tot;
    int newnode()
        tr[++tot].init();
        return tot;
    
    void init()
        tot = 0; 
        root = newnode();
    
    void insert(string s, int v)
        int len = s.size();
        int u = root;
        for(int i = 0; i < len; i++)
            if(tr[u].ch[s[i]-'a'] == -1)
                tr[u].ch[s[i]-'a'] = newnode();
            
            u = tr[u].ch[s[i]-'a'];
        
        tr[u].v += v;
        tr[u].cnt++;
    
    int query(string s)
        int len = s.size();
        int u = root;
        for(int i = 0; i < len; i++)
            if(tr[u].ch[s[i]-'a'] == -1)return -1;
            u = tr[u].ch[s[i]-'a'];
        
        if(tr[u].cnt==0)return -1;
        return tr[u].v;
    
tire;


string a[1010];

int main()
    IOS;
    int T;  cin>>T;
    while(T--)
        tire.init();
        int n, m;  cin>>n>>m;
        for(int i = 0; i < n; i++)cin>>a[i];
        for(int i = 1; i <= m; i++)
            string s;  int v;  cin>>s>>v;
            tire.insert(s, v);
        
        //solve
        LL res = 0;
        int ok = 0;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                string tmp = "";
                if(a[i][j] == '#')continue;
                while(a[i][j]!='#' && j < n)
                    tmp += a[i][j++];
                
                LL now = tire.query(tmp);
                if(now == -1)cout<<"-1\\n"; ok = 1; break; 
                res += now;
            
            if(ok)break;
        
        if(ok==1)ZJCPC2022 第19届 浙江省赛The 19th Zhejiang Provincial Collegiate Programming Contest(CBALGMIF 8题)

ZJCPC2018 第15届 浙江省赛The 15th Zhejiang Provincial Collegiate Programming Contest(MABLJK 6题)

ZJCPC2018 第15届 浙江省赛The 15th Zhejiang Provincial Collegiate Programming Contest(MABLJK 6题)

ZJCPC2019 第16届 浙江省赛The 16th Zhejiang Provincial Collegiate Programming Contest(GFHIJ 5题)

ZJCPC2019 第16届 浙江省赛The 16th Zhejiang Provincial Collegiate Programming Contest(GFHIJ 5题)

ZJCPC2021 第18届 浙江省赛The 18th Zhejiang Provincial Collegiate Programming Contest(ACFGJLM 7题)