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)