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)

(c)2006-2024 SYSTEM All Rights Reserved IT常识