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\)次,此時我們取樹的重心為帶權重心即可。
那麼可以列出式子:
\[f(s)=\sum_{i=0}^m{s\choose i}{n-s\choose m-i}\cdot min(i, m-i) \]
這就是題解中的式子,因為式子中含有min,我們可以直接將其拆開,就有題解中的式子(令\(p=\frac{m-1}{2}\)):
\[f(s)=\sum_{i=1}^p({s\choose i}{n-s\choose m-i}\cdot i+{s\choose m-i}{n-s\choose i}\cdot i)+[m\% 2]\cdot {s\choose m/2}{n-s\choose m/2}\cdot(m/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;
}