2021.2.10 校队训练纪念戳
诶诶诶怎么大年二十九还训练啊qwq
不得不说 感觉这套题好难读题啊qwq 因为我英语太差了qwq??
慢速补题中qwq
A- Advertisement Matching
B- Bombs In My Deck
比较签到的一个题,直接用一个搜索就完事了。
但是注意30的阶乘是大于long long范围的!
实测:20!还在long long范围内,但是21!就超过了qwq
#include<bits/stdc++.h>
using namespace std;
double ans1, ans2;
inline void solve(double x, int a, int b, int c){
if(a <= 0) return;
double cur_ans = x * b / a;
if(b > 0) {
if(c <= 5) ans1 += cur_ans;
else solve(cur_ans, a - 1, b - 1, c - 5);
}
return;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("ce.in", "r", stdin);
#endif
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
ans2 = 1.0;
for(int i = 2; i <= a; i++) ans2 *= i;
solve(ans2, a, b, c);
printf("%.7lf\n", (ans2 - ans1) / ans2);
return 0;
}
C- Economic One-way Roads
D- Fix Wiring
题目大意:有n个点,连一张完全图。现在有n*(n-1)/2个值,你需要由某种策略给每条边赋上这些值,使得建立一个最小生成树的费用最小 和 最大(两问),求最小值和最大值是多少。
最小值显然就是选前n-1条最小的边。
最大值就是我们需要使得小的边尽可能没用。那么我们假设最小生成树应当是从点1连点2,点2连点3…点n-1连点n,我们每次按次序往里面加一个点。
我们可以发现,每次加入一个点的时候,总要向前n-1个点连边。而此时,举个例子来说,如果点i连上了通往点1的边,那么点1到点i这条中间按着顺序直接连的i-1条边中有可能就有一条边不再是最小生成树上的边。
那么我们就有做题策略了,将边从小到大排序之后进行使用。按照次序加点,每次点i向前连边,一直连到通往点1的边(这样是保证i到i-1的边是最小边以使其一定在最小生成树上)。
#include<bits/stdc++.h>
#define MAXN 200010
using namespace std;
int n, m;
int a[MAXN];
long long ans1, ans2;
int main(){
#ifndef ONLINE_JUDGE
freopen("ce.in", "r", stdin);
#endif
scanf("%d", &n);
m = n * (n - 1) / 2;
for(int i = 1; i <= m; i++) scanf("%d", &a[i]);
sort(&a[1], &a[m + 1]);
for(int i = 1; i <= n - 1; i++) ans1 += a[i];
int cnt = 0;
for(int i = 2; i <= n; i++){
for(int j = i - 1; j >= 1; j--){
cnt++;
if(i == j + 1) ans2 += a[cnt];
}
}
printf("%lld %lld\n", ans1, ans2);
return 0;
}
E- Min-hashing
每个点的l都是不同的,所以在每一个联通块里都是最小值尽可能多的往外传。
如果当前联通块最小值ai在i点,那么对于一个点j来说,它第一次变成ai是在第dis(i,j)次,在这一次之后再传偶数次可以保证它的值还是ai,但是奇数次就不一定是。
所以在k次之后,如果原图是一个二分图的话,就会分成两类,一类是奇数次能够传到,一类是偶数次能被传到。我们对于两类分别计数。
如果不是的话,那么就有至少一条边可以做到奇偶互换,所以无数多次之后整个联通块都会变成一样的最小值。我们对联通块内所有节点进行计数。
#include<bits/stdc++.h>
#define MAXN 300010
#define MAXM 500010
using namespace std;
int n, m, t;
int a[MAXN], head[MAXN], color[MAXN];
long long ans;
long long cnt[3];
struct Edge{
int nxt, to;}edge[MAXM << 1];
inline void add(int from, int to){
edge[++t].nxt = head[from], edge[t].to = to;
head[from] = t;
}
inline bool solve(int x, int tmp){
bool flag = true;
color[x] = tmp;
cnt[tmp]++;
for(int i = head[x]; i; i = edge