zoukankan      html  css  js  c++  java
• # 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;
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 << '
';
}
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]<<'
';
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int _=1;
cin>>_;
while(_--)run();
return 0;
}
``````

### G. Go Running

考虑建图，从左往右的情况连边，会有若干条链；从右往左也是。并且链的斜率都为正负1。
那么考虑将这个图旋转一下变为网格图，要求的就是选择最少的行、列来覆盖这个网格图。这就是一个最小点覆盖的问题。
使用dinic跑最大流复杂度为(O(nsqrt{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;
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 << "]
";}
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 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) {
}
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++) {
}
for (int i = tx; i < ty; i++) {
}
for (int i = 1; i <= n; i++) {
}
int ans = solver.dinic(S, T);
cout << ans << '
';
}
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)个人，然后他们会走到某个点上面去，代价为所有人经过的边数之和。
一共会有(nchoose m)种情况，现在要计算所有情况代价最小的和为多少。

思路：
显然直接算十分麻烦，因为枚举重心的话会涉及很多情况。所以转化一下思维：

• 考虑每一条边的贡献。

对于一条边来说，假设一边有(x)个人，另外一边有(y)个人，(x<y)，那么最优方案一定会贡献(min(x,y)=x)次，此时我们取树的重心为带权重心即可。
那么可以列出式子：

[f(s)=sum_{i=0}^m{schoose i}{n-schoose m-i}cdot min(i, m-i) ]

这就是题解中的式子，因为式子中含有min，我们可以直接将其拆开，就有题解中的式子(令(p=frac{m-1}{2}))：

[f(s)=sum_{i=1}^p({schoose i}{n-schoose m-i}cdot i+{schoose m-i}{n-schoose i}cdot i)+[m\% 2]cdot {schoose m/2}{n-schoose m/2}cdot(m/2) ]

后面那一部分暂时不用管，前面的两部分其实是具有对称性，我们令(s'=n-s)即可很轻松发现是具有对称关系的。
因此我们先考虑前一部分：(displaystyle g(s)=sum_{i=1}^p{schoose i}{n-schoose m-i}cdot i)，显然后面就等于(g(n-s))
我们可以把(i)消去：(displaystyle g(s)=scdot sum_{i=1}^p{s-1choose i-1}{n-schoose 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 << "]
";}
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 = 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) {
if (m % 2 == 0) {
int tmp = 1ll * (m / 2) * C(s, m / 2) % MOD * C(n - s, m / 2) % MOD;
}
}
}
cout << res << '
';
}
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;
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 << '
';
}
}
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;
}
``````
• 相关阅读:
[LeetCode] Valid Palindrome