- Contest Info
- Solutions
- A - Balloon Robot
- B - Expected Waiting Time
- C - Crusaders Quest
- D - Graph Generator
- E - String of CCPC
- G - Numbers
- H - Prime Set
- L - One-Dimensional Maze
Contest Info
传送门
Solved |
A |
B |
C |
D |
E |
F |
G |
H |
I |
J |
K |
L |
M |
9 / 13 |
O |
Ø |
O |
Ø |
O |
- |
O |
Ø |
- |
- |
- |
O |
O |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
A - Balloon Robot
题意:
\(n\)个人,\(m\)个座位组成一个圆环,\(1\leq n\leq 10^5,n\leq m\leq 10^9\)。
现在有\(q,q\leq 10^5\)个事件,表示第\(i\)个人在\(t_i\)时刻A了一道题。
\(s_i\)表示每个人的位置。
现在有个机器人,可以选定他开始的位置,时刻从\(1\)开始。之后他会顺时针走,每一秒走一步。如果他在某一个位置时这个人目前已经A了题,他将会发放气球。
记一个人的怒气值为\(得到气球的时间-A题的时间\)。
现在问起点选择哪个点使得所有人的怒气值之和最少。
思路:
- 机器人起点肯定位于某个人的位置,所以起点一共有\(n\)个。
- 每个事件对答案的贡献不会超过\(m\),其实可以将问题转化为一个模\(m\)意义下的问题。
- 先求出机器人一开始位于\(1\)位置的答案。之后枚举每个可能的起点计算答案即可。
- 机器人每移动一位所有事件的贡献在模意义下将减少\(1\),就相当于总答案减少\(p\)。那么枚举起点就可以\(O(1)\)转移答案了。
主要关键点在于将问题转化为模意义下的问题。
细节见代码:
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/18 16:22:01
*/
#include
#include
#include
#include
#include
#include
#include
#include
B - Expected Waiting Time
题意:
先有\(n\)个面试者,有\(2n\)个时刻表示每个面试者到来的时间以及面试官选择面试的时间(顺序不确定)。
当等候室内的人数不小于\(1\)时,面试官能够选择某个时间随机挑选一个人进行面试,最后\(n\)个人都要面试完。
设\(A\)为某个人到达的时间,\(S\)为面试官选择面试的事件,那么在任意一个时刻\(A\)的数量不小于\(S\)。显然有若干个合法的序列。最后求所有面试者等待的时间期望之和的平均值。
思路:
考虑对于任意一种合法的序列,期望之和为多少。显然此时和是不会改变的,不会因为面试官的选择而改变。那么面试官的随机选择我们可以看作一个固定选择,问题即转化为进出栈问题。
显然我们不可能枚举所有的情况,所以对于直接考虑一个位置为左括号、右括号的贡献,那么接下来我们只需要求出对应的情况数就行。接下来以右括号举例,左括号将序列翻转即可。
假设我们枚举到了位置\(j\),显然左边有个括号要与其匹配,我们枚举所有可能的位置\(j-1,j-3,j-5...\),从这些位置转移。那么中间的那些一定匹配成功,外面的那些也要匹配成功,所以就转化为了两个卡特兰数的乘积。即:
\[dp[j]=\sum_{i=j-1,i-=2}cat(\frac{i-j-1}{2})\cdot cat(\frac{n-(i-j+1)}{2}) \]
直接来求复杂度比较蛋疼。
注意到\(dp[j]=dp[j-2]+某一项\)。所以这样就可以\(O(n)\)枚举得到\(dp\)数组了。
接下来就很好办了,就按照刚刚的转化过程,逆着写得到期望之和就行。最后还要除以一个\(cat(n)\)。
代码如下:
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/20 16:34:50
*/
#include
#include
#include
#include
#include
#include
#include
#include
C - Crusaders Quest
签到。状压枚举所有情况即可。
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/18 13:21:12
*/
#include
#include
#include
#include
#include
#include
#include
#include
D - Graph Generator
题意:
如果已知一个排列\(p\),第\(i\)次操作产生\(p_i\)。然后可以选定目前图中若干个连通块,将\(p_i\)与连通块中所有的点进行连边。
现在给定最后的图,问是否存在一个\(p\)和每次选择的集合,使得最终能够得到这个图。
\(n,m\leq 10^5\)。
思路:
这种题从前往后很难构造,我们可以考虑从后往前在图中删点往前推。
观察到在一个连通块内,每次必然会先选择度数最大的点,因为当前选择的点要与其它所有点进行连边(注意是连通块)。
又有一个观察:每次去掉一个点后,其余所有的点度数都会减\(1\),也就是说度数的相对大小不变。
根据这两点做法呼之欲出了,我们只需要按照度数从大到小来处理。但现在还有个问题,连通块的问题,我们需要知道当前点所在连通块的size。
这种一般是并查集,但这里是删边,不好处理。所以。。直接上可撤销并查集就行了。先正着跑一遍,然后往前操作时不断从栈中取出之前状态进行还原。这样我们就能得到每一个时刻的连通状况。注意不能路径压缩,只能按秩合并。
细节见代码:
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/20 12:57:42
*/
#include
#include
#include
#include
#include
#include
#include
#include
E - String of CCPC
签到。答案最多增加\(1\),随便乱搞即可。
Code
#include
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ld;
const int MAXN = 2e5 + 5, MAXM = 4e5 + 5, BOUND = 2e5, MOD = 1e9+7, INF = 0x3f3f3f3f, base = 10000;
const int inv2 = (MOD + 1) >> 1;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0), eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define lc(x) ch[x][0]
#define pii pair
#define vi vector
#define vii vector>
#define rc(x) ch[x][1]
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(a) (a).begin(), (a).end()
#define sz(a) int(a.size())
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fi first
#define se second
#define MP std::make_pair
#define ri register int
//#define sz(a) int((a).size())
inline int add(int a, int b) {return a + b >= MOD ? a + b - MOD : a + b;}
inline int dec(int a, int b) {return a < b ? a - b + MOD : a - b;}
inline int mul(int a, int b) {return 1ll * a * b % MOD;}
template
inline void cmin(T &a,T b){a = min(a,b);}
template
inline void cmax(T &a,T b){a = max(a,b);}
ll qpow(ll a,ll b){
ll ans=1;
for(;b;b>>=1,a=a*a%MOD)if(b&1)ans=ans*a%MOD;
return ans;
}
mt19937 mrand(random_device{}());
char s[MAXN];
int mp[5][2] = {{1,0},{2,0},{2,3},{4,0},{2,0}};
void run(){
int n;cin>>n;
cin>>(s+1);
int ans=0,sta=0;
bool flag=false;
rep(i,1,n){
if(sta==2 && s[i]=='C'){
if(!flag){
flag=true;
ans++;
}
}
if(sta==1 && s[i]=='P' && i+1<=n && s[i+1]=='C'){
if(!flag){
flag=true;
ans++;
//cout<<"lalala\n";
}
}
if(s[i]=='C'){
sta = mp[sta][0];
}else if(s[i]=='P'){
sta = mp[sta][1];
}
if(sta==4)ans++;
if(i==n && sta==3){
if(!flag){
flag=true;
ans++;
}
}
//cout<>_;
while(_--)run();
return 0;
}
G - Numbers
二进制位从高到低贪心即可。涉及到大数,所以用的python。
Code
t = int(input())
for i in range(t):
n, m = map(int, input().split())
pw = []
i = 1
while i <= n:
pw.append(i)
i *= 2
ans = 0
mx = 0
for i in range(len(pw)-1, -1, -1):
if mx + m*(pw[i]-1) < n:
ans += pw[i]
mx += min(m, (n-mx)//pw[i])*pw[i]
#print(pw[i], mx)
print(ans)
H - Prime Set
题意:
定义一个素数集为\(\{i,j\}\)并且\(a_i+a_j\)为素数。
给定序列\(a\),现从中选择至多\(k\)个素数集,使得并起来的元素个数最多。
\(n\leq 10^3,0\leq k\leq \frac{n\cdot(n-1)}{2}\)。
思路:
利用“两个数加起来为素数”这个条件,我们容易发现除开\(1+1=2\)这种情况,其余都是一奇一偶。这有点二分图的意思。
所以考虑建二分图,奇数在左边,偶数在右边,然后按照题意要求进行连边求个最大匹配即可。
注意\(1\)的存在比较特殊,应该最后再从\(1\)出发跑增广路。这样答案能够更优。
最后再\((1,1)\)进行匹配。
细节见代码:
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/18 19:30:23
*/
#include
#include
#include
#include
#include
#include
#include
#include
L - One-Dimensional Maze
签到。
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/18 13:08:04
*/
#include
#include
#include
#include
#include
#include
#include
#include