2020 Multi-University Training Contest 4
Contest Info
Solved | A | B | C | D | E | F | G | H | I | J | K | L |
---|---|---|---|---|---|---|---|---|---|---|---|---|
8 / 12 | - | O | Ø | O | O | - | Ø | - | Ø | - | O | Ø |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
B. Blow up the Enemy
签到。
Code
// Author : heyuhhh
// Created Time : 2020/07/30 12:48:55
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
const double eps = 1e-7;
void run() {
int n;
cin >> n;
vector<int> a(n), d(n);
vector<int> t(n);
for (int i = 0; i < n; i++) {
cin >> a[i] >> d[i];
int nd = (100 + a[i] - 1) / a[i];
t[i] = (nd - 1) * d[i];
}
double ans = 0;
for (int i = 0; i < n; i++) {
double res = 0;
for (int j = 0; j < n; j++) {
if (fabs(t[i] - t[j]) < eps) {
res += 0.5;
} else if (t[i] > t[j] + eps) {
} else {
res += 1;
}
}
res /= 1.0 * n;
ans = max(ans, res);
}
cout << ans << '\n';
}
int main() {
#ifdef Local
freopen("input.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(10);
int T; cin >> T; while(T--)
run();
return 0;
}
C. Contest of Rope Pulling
直接随机一下,然后一个是正贡献、一个是负贡献,做个背包就行,可以设定一个上限大概为根号级别。应该就可以过了。。
D. Deliver the Cake
跑个带有两个附加状态的最短路就行。
E. Equal Sentences
dp一下。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ld;
const int MAXN = 1e5 + 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 mid l+((r-l)>>1)
#define lc(x) ch[x][0]
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pair<int,int>>
#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 <typename T>
inline void cmin(T &a,T b){a = min(a,b);}
template <typename T>
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{}());
string s[MAXN];
int f[MAXN];
void run(){
int n; cin>>n;
rep(i,1,n){
cin>>s[i];
}
f[0] = 1;
rep(i,1,n){
f[i] = f[i-1];
if(s[i] != s[i-1])f[i] = add(f[i], f[i-2]);
}
cout<<f[n]<<'\n';
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int _=1;
cin>>_;
while(_--)run();
return 0;
}
G. Go Running
考虑建图,从左往右的情况连边,会有若干条链;从右往左也是。并且链的斜率都为正负1。
那么考虑将这个图旋转一下变为网格图,要求的就是选择最少的行、列来覆盖这个网格图。这就是一个最小点覆盖的问题。
使用dinic跑最大流复杂度为\(O(n\sqrt{n})\),并且上界也比较松。
Code
// Author : heyuhhh
// Created Time : 2020/07/30 14:08:31
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
void err(int x) {cerr << x;}
void err(long long x) {cerr << x;}
void err(double x) {cerr << x;}
void err(char x) {cerr << '"' << x << '"';}
void err(const string &x) {cerr << '"' << x << '"';}
void _print() {cerr << "]\n";}
template<typename T, typename V>
void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
template<typename T>
void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
template <typename T, typename... V>
void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
#ifdef Local
#define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define dbg(x...)
#endif
const int N = 4e5 + 5;
int n;
template <class T>
struct Dinic{
struct Edge{
int v, next;
T flow;
Edge(){}
Edge(int v, int next, T flow) : v(v), next(next), flow(flow) {}
}e[N << 1];
int head[N], tot;
int dep[N];
void init() {
memset(head, -1, sizeof(int) * (2 * n + 10)); tot = 0;
}
void adde(int u, int v, T w, T rw = 0) {
e[tot] = Edge(v, head[u], w);
head[u] = tot++;
e[tot] = Edge(u, head[v], rw);
head[v] = tot++;
}
bool BFS(int _S, int _T) {
memset(dep, 0, sizeof(dep));
queue <int> q; q.push(_S); dep[_S] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].v;
if(!dep[v] && e[i].flow > 0) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return dep[_T] != 0;
}
T dfs(int _S, int _T, T a) {
T flow = 0, f;
if(_S == _T || a == 0) return a;
for(int i = head[_S]; ~i; i = e[i].next) {
int v = e[i].v;
if(dep[v] != dep[_S] + 1) continue;
f = dfs(v, _T, min(a, e[i].flow));
if(f) {
e[i].flow -= f;
e[i ^ 1].flow += f;
flow += f;
a -= f;
if(a == 0) break;
}
}
if(!flow) dep[_S] = -1;
return flow;
}
T dinic(int _S, int _T) {
T max_flow = 0;
while(BFS(_S, _T)) max_flow += dfs(_S, _T, INF);
return max_flow;
}
};
Dinic<int> solver;
void run() {
cin >> n;
map<int, vector<int>> lr, rl;
for (int i = 0; i < n; i++) {
int t, x;
cin >> t >> x;
lr[x - t].push_back(i + 1);
rl[x + t].push_back(i + 1);
}
// y = x + c
// x2 - x1 = t2 - t1
// y = -x + c
// x2 - x1 = t1 - t2
vector<int> x(n + 1), y(n + 1);
int tx = 1, ty;
for (auto& it : lr) {
for (auto& it2 : it.se) {
x[it2] = tx;
}
++tx;
}
ty = tx;
for (auto& it : rl) {
for (auto& it2 : it.se) {
y[it2] = ty;
}
++ty;
}
int S = 0, T = ty;
solver.init();
for (int i = 1; i < tx; i++) {
solver.adde(S, i, 1);
}
for (int i = tx; i < ty; i++) {
solver.adde(i, T, 1);
}
for (int i = 1; i <= n; i++) {
solver.adde(x[i], y[i], 1);
}
int ans = solver.dinic(S, T);
cout << ans << '\n';
}
int main() {
#ifdef Local
freopen("input.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T; while(T--)
run();
return 0;
}
I. Imperative Meeting
题意:
给定一颗无根树,在上面放置\(m\)个人,然后他们会走到某个点上面去,代价为所有人经过的边数之和。
一共会有\(n\choose m\)种情况,现在要计算所有情况代价最小的和为多少。
思路:
显然直接算十分麻烦,因为枚举重心的话会涉及很多情况。所以转化一下思维:
- 考虑每一条边的贡献。
对于一条边来说,假设一边有\(x\)个人,另外一边有\(y\)个人,\(x<y\),那么最优方案一定会贡献\(min(x,y)=x\)次,此时我们取树的重心为带权重心即可。
那么可以列出式子:
这就是题解中的式子,因为式子中含有min,我们可以直接将其拆开,就有题解中的式子(令\(p=\frac{m-1}{2}\)):
后面那一部分暂时不用管,前面的两部分其实是具有对称性,我们令\(s'=n-s\)即可很轻松发现是具有对称关系的。
因此我们先考虑前一部分:\(\displaystyle g(s)=\sum_{i=1}^p{s\choose i}{n-s\choose m-i}\cdot i\),显然后面就等于\(g(n-s)\)。
我们可以把\(i\)消去:\(\displaystyle g(s)=s\cdot \sum_{i=1}^p{s-1\choose i-1}{n-s\choose m - i}\)。
我们可以给其赋予组合意义,就是\(n-1\)个盒子要放\(m-1\)个小球,前面\(s-1\)个位置最多放\(p-1\)个小球的方案数。
因为最后答案是跟\(s\)有关,注意这是一个前缀,其它数不会改变,那么就可以通过递推求得所有的\(g(s)\)。
剩下的就简单了。
Code
// Author : heyuhhh
// Created Time : 2020/08/06 10:41:24
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
void err(int x) {cerr << x;}
void err(long long x) {cerr << x;}
void err(double x) {cerr << x;}
void err(char x) {cerr << '"' << x << '"';}
void err(const string &x) {cerr << '"' << x << '"';}
void _print() {cerr << "]\n";}
template<typename T, typename V>
void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
template<typename T>
void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
template <typename T, typename... V>
void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
#ifdef Local
#define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define dbg(x...)
#endif
//head
const int N = 1e6 + 5, MOD = 1e9 + 7;
int qpow(ll a, ll b) {
ll res = 1;
while(b) {
if(b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int fac[N], inv[N];
void init() {
fac[0] = 1;
for(int i = 1; i < N; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
inv[N - 1] = qpow(fac[N - 1], MOD - 2);
for(int i = N - 2; i >= 0; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
}
int C(int n, int m) {
if (n < m || n < 0 || m < 0) return 0;
return 1ll * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
void add(int& x, int y) {
x += y;
if (x >= MOD) x -= MOD;
}
int f[N], sz[N];
int n, m;
int ans[N];
void run() {
cin >> n >> m;
for (int i = 2; i <= n; i++) {
cin >> f[i];
}
int p = (m - 1) / 2;
ans[1] = C(n - 1, m - 1);
for (int i = 2; i <= n; i++) {
int t = 1ll * C(i - 2, p - 1) * C(n - i, m - 1 - p) % MOD;
ans[i] = (ans[i - 1] - t + MOD) % MOD;
}
if (p == 0) {
for (int i = 1; i <= n; i++) {
ans[i] = 0;
}
}
for (int i = 1; 2 * i <= n; i++) {
ans[i] = 1ll * ans[i] * i % MOD + 1ll * ans[n - i] * (n - i) % MOD;
ans[i] %= MOD;
}
for (int i = 1; i <= n; i++) {
sz[i] = 1;
}
for (int i = n; i > 1; i--) {
sz[f[i]] += sz[i];
}
int res = 0;
for (int i = 1; i <= n; i++) {
int s = sz[i];
if (s < n) {
add(res, ans[min(s, n - s)]);
if (m % 2 == 0) {
int tmp = 1ll * (m / 2) * C(s, m / 2) % MOD * C(n - s, m / 2) % MOD;
add(res ,tmp);
}
}
}
cout << res << '\n';
}
int main() {
#ifdef Local
freopen("input.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
init();
int T; cin >> T; while(T--)
run();
return 0;
}
K. Kindergarten Physics
引力没啥影响,所以直接输出。
L. Last Problem
考虑递归进行构造,但是如果直接硬上的话可能时间会炸掉。但是稍微手模一下就会发现有很多共用的部分是不用管的,这样就节约掉了很大的时间。所以对于位置记忆化一下就行。当然还要选择一个较优的策略,但是这个策略其实挺多的。
相减代码:
Code
// Author : heyuhhh
// Created Time : 2020/07/30 20:05:17
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 5000 + 5;
int mp[N][N];
void run() {
int n;
cin >> n;
vector<pair<pii, int>> ans;
function <void(int, int, int)> draw = [&] (int x, int y, int n) {
if (mp[x][y] == n) return;
if (n <= 0) return;
if (n == 1) {
ans.emplace_back(MP(MP(x, y), 1));
mp[x][y] = 1;
return;
}
draw(x, y + 1, n - 1);
draw(x - 1, y, n - 2);
draw(x + 1, y, n - 3);
draw(x, y - 1, n - 4);
ans.emplace_back(MP(MP(x, y), n));
mp[x][y] = n;
return;
};
draw(2000, 2000, n);
for (auto it : ans) {
cout << it.fi.fi << ' ' << it.fi.se << ' ' << it.se << '\n';
}
}
int main() {
#ifdef Local
freopen("input.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
重要的是自信,一旦有了自信,人就会赢得一切。