2020 Multi-University Training Contest 1
目錄
Contest Info
Solved | A | B | C | D | E | F | G | H | I | J | K | L |
---|---|---|---|---|---|---|---|---|---|---|---|---|
5 / 12 | - | - | - | O | Ø | Ø | - | - | Ø | - | Ø | - |
- O 在比賽中通過
- Ø 賽後通過
- ! 嘗試了但是失敗了
- - 沒有嘗試
Solutions
D. Distinct Sub-palindromes
對於\(n>3\)
Code
// Author : heyuhhh // Created Time : 2020/07/22 16:16:09 #include<bits/stdc++.h> using namespace std; void run() { int n; cin >> n; if (n == 1) { cout << 26 << '\n'; } else if (n == 2) { cout << 26 * 26 << '\n'; } else if (n == 3) { cout << 26 * 26 * 26 << '\n'; } else { cout << 26 * 25 * 24 << '\n'; } } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T; cin >> T; while(T--) run(); return 0; }
E. Fibonacci Sum
弱化版在這裡:傳送門。
主要思路是在模數為\(1e9+9\)的情況下\(5\)存在二次剩餘,所以可以直接通過通項計算斐波那契數列。
因為這個題有\(k\)次方,所以根據二項式定理展開後交換求和式就容易得到為一系列等比數列的求和。
然後這個題就可以\(O(k)\)解決(忽略快速冪)。
但是這個題存在卡常問題,所以要很多優化,比如尤拉降冪、int、以及將式子中的\(a^i\cdot b^{k-i}\)變為\((\frac{a}{b})^i\cdot b^k\)然後逐項遞推求解等。
詳見程式碼:
Code
// Author : heyuhhh // Created Time : 2020/07/21 13:25:57 #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, MOD = 1e9 + 9; const int A = 691504013, B = 308495997, sqrt5 = 383008016, inv5 = 276601605; template <class T> inline void rd(T& x) { x = 0; char k = getchar(); while (k > '9' || k < '0') k = getchar(); while (k <= '9' && k >= '0') x = x * 10 + k - 48, k = getchar(); } inline int qpow(ll a, ll b) { ll res = 1; if (a >= MOD) a %= MOD; // if (a > 0) { // b %= (MOD - 1); // } else if (b >= MOD - 1) { // b = b % (MOD - 1) + MOD - 1; // } while(b) { if (b & 1) res = res * a % MOD; a = a * a % MOD; b >>= 1; } return res; } int fac[N], inv[N], tmp[N]; inline void init() { fac[0] = 1; for(int i = 1; i < N; i++) fac[i] = 1ll * fac[i - 1] * i % MOD; tmp[0] = tmp[1] = inv[0] = inv[1] = 1; for (int i = 2; i < N; i++) { tmp[i] = 1ll * (MOD - MOD / i) * tmp[MOD % i] % MOD; inv[i] = 1ll * inv[i - 1] * tmp[i] % MOD; } } inline int C(int n, int m) { return 1ll * fac[n] * inv[m] % MOD * inv[n - m] % MOD; } ll n, c, k; inline void run() { rd(n), rd(c), rd(k); ll ans = 0; int cv = qpow(inv5, k); int d = qpow(1ll * A * qpow(B, MOD - 2) % MOD, c); int b = qpow(qpow(B, k), c); int dd = qpow(d, n + 1); int bb = qpow(b, n + 1); int s1 = 1, s2 = 1; for (int i = 0; i <= k; ++i) { int res = C(k, i); int t = 1ll * b * s1 % MOD; if (t == 1) { res = 1ll * ((n + 1) % MOD) * res % MOD; } else { int fm = qpow(t - 1, MOD - 2); int fz = 1ll * bb * s2 % MOD - 1 + MOD; res = 1ll * res * fz % MOD * fm % MOD; } if ((k - i) & 1) ans -= res; else ans += res; s1 = 1ll * s1 * d % MOD; s2 = 1ll * s2 * dd % MOD; } ans = ans % MOD * cv % MOD; if (ans < 0) ans += MOD; printf("%lld\n", ans); } int main() { #ifdef Local freopen("input.in", "r", stdin); #endif init(); int T; rd(T); while(T--) run(); return 0; }
F. Finding a MEX
題意:
給出一張\(n\)個點\(m\)條邊的無向圖,每個點都有一個點權\(f(i)\)。
現有兩種操作:
- \(1\ u\ x\),將\(f(u)\)改為\(x\);
- \(2\ u\),計算\(mex\{f(v)\},(u,v)\in edges\)。
思路:
類似的圖論問題一般可以根據握手定理然後按度數分塊來解決。因為會有這樣一個性質:
- 假設按照度數為\(S\)大小分塊,那麼小度點度數不超過\(S\),大度點個數不會超過\(\frac{2m}{S}\)。
然後根據以上性質就可以較為暴力地解決一些問題,比如這個題。
我們對每個點維護一個\(set\)(也可以線段樹、樹狀陣列什麼的),然後查詢的話就在\(O(logn)\)的時間可以解決,對於修改,小度點就暴力修改周圍的所有邊,大度點就先不管。那麼對於一個點的查詢還得加上週圍得大度點,所以查詢的複雜度為\(O(Slogn)\)的。
這裡取\(S=\sqrt{2m\cdot logn}\)會比較快。總的複雜度為\(O(n\sqrt{S} log)\)。
實際上還有\(O(n\sqrt{n})\)的做法,但我跑出來貌似和上述做法速度差不多。。具體的做法就是將\(set\)換作分塊,也就是我們對資訊進行分塊,這樣可以\(O(1)\)增添資訊。那麼查詢時複雜度為\(O(\sqrt{n})\),修改時小度點進行修改複雜度為\(O(\sqrt{n})\),之後詢問列舉大度點複雜度為\(O(\sqrt{n})\)。所以總的時間複雜度為\(O(n\sqrt{n})\)的。
細節見程式碼:
Code
// Author : heyuhhh
// Created Time : 2020/07/22 10:47:45
#pragma GCC optimize(2)
#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 = 1e5 + 5;
#define FI(n) FastIO::read(n)
#define FO(n) FastIO::write(n)
#define Flush FastIO::Fflush()
namespace FastIO {
const int SIZE = 1 << 16;
char buf[SIZE], obuf[SIZE], str[60];
int bi = SIZE, bn = SIZE, opt;
double D[] = {0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001, 0.0000000001};
int read(char *s) {
while (bn) {
for (; bi < bn && buf[bi] <= ' '; bi++);
if (bi < bn) break;
bn = fread(buf, 1, SIZE, stdin);
bi = 0;
}
int sn = 0;
while (bn) {
for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
if (bi < bn) break;
bn = fread(buf, 1, SIZE, stdin);
bi = 0;
}
s[sn] = 0;
return sn;
}
bool read(int& x) {
int n = read(str), bf = 0;
if (!n) return 0;
int i = 0; if (str[i] == '-') bf = 1, i++; else if (str[i] == '+') i++;
for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
if (bf) x = -x;
return 1;
}
bool read(long long& x) {
int n = read(str), bf;
if (!n) return 0;
int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1;
for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
if (bf < 0) x = -x;
return 1;
}
void write(int x) {
if (x == 0) obuf[opt++] = '0';
else {
if (x < 0) obuf[opt++] = '-', x = -x;
int sn = 0;
while (x) str[sn++] = x % 10 + '0', x /= 10;
for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
}
if (opt >= (SIZE >> 1)) {
fwrite(obuf, 1, opt, stdout);
opt = 0;
}
}
void write(long long x) {
if (x == 0) obuf[opt++] = '0';
else {
if (x < 0) obuf[opt++] = '-', x = -x;
int sn = 0;
while (x) str[sn++] = x % 10 + '0', x /= 10;
for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
}
if (opt >= (SIZE >> 1)) {
fwrite(obuf, 1, opt, stdout);
opt = 0;
}
}
void write(unsigned long long x) {
if (x == 0) obuf[opt++] = '0';
else {
int sn = 0;
while (x) str[sn++] = x % 10 + '0', x /= 10;
for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
}
if (opt >= (SIZE >> 1)) {
fwrite(obuf, 1, opt, stdout);
opt = 0;
}
}
void write(char x) {
obuf[opt++] = x;
if (opt >= (SIZE >> 1)) {
fwrite(obuf, 1, opt, stdout);
opt = 0;
}
}
void Fflush() { if (opt) fwrite(obuf, 1, opt, stdout); opt = 0;}
};
int n, m;
int a[N];
vector<int> G[N], bG[N];
int bsz;
struct Block {
int Bnum, E, V;
vector<int> Bcnt;
vector<int> Bbel;
vector<int> Bres;
vector<pii> Bdiv;
void init(int x) {
V = sz(G[x]) + 1;
E = sqrt(V + 0.5);
Bnum = 0;
Bcnt.assign(V + 1, 0);
Bbel.assign(V + 1, -1);
Bdiv.clear();
Bres.clear();
for (int i = 0; i <= V; i += E, ++Bnum) {
for (int j = i; j <= min(V, i + E - 1); j++) {
Bbel[j] = Bnum;
}
Bdiv.emplace_back(i, min(i + E - 1, V));
Bres.push_back(0);
}
}
void add(int x) {
if (x > V) return;
++Bcnt[x];
if (Bcnt[x] == 1) {
++Bres[Bbel[x]];
}
}
void del(int x) {
if (x > V) return;
--Bcnt[x];
if (Bcnt[x] == 0) {
--Bres[Bbel[x]];
}
}
int query() {
for (int i = 0; i < Bnum; i++) {
if (Bdiv[i].se - Bdiv[i].fi + 1 != Bres[i]) {
for (int j = Bdiv[i].fi; j <= Bdiv[i].se; j++) {
if (!Bcnt[j]) {
return j;
}
}
}
}
}
}blk[N];
void run() {
FI(n), FI(m);
bsz = sqrt(m + 0.5);
for (int i = 1; i <= n; i++) {
FI(a[i]);
G[i].clear();
bG[i].clear();
}
for (int i = 1; i <= m; i++) {
int u, v;
FI(u), FI(v);
G[u].push_back(v);
G[v].push_back(u);
}
for (int i = 1; i <= n; i++) {
blk[i].init(i);
}
for (int i = 1; i <= n; i++) {
for (auto j : G[i]) {
if (sz(G[j]) > bsz) {
bG[i].push_back(j);
}
if (sz(G[i]) <= bsz) {
blk[j].add(a[i]);
}
}
}
int q;
FI(q);
while (q--) {
int op;
FI(op);
if (op == 1) {
int u, x;
FI(u), FI(x);
if (sz(G[u]) <= bsz) {
for (auto v : G[u]) {
blk[v].del(a[u]);
blk[v].add(x);
}
}
a[u] = x;
} else {
int u;
FI(u);
for (auto v : bG[u]) {
blk[u].add(a[v]);
}
int ans = blk[u].query();
FO(ans), FO('\n');
for (auto v : bG[u]) {
blk[u].del(a[v]);
}
}
}
}
int main() {
#ifdef Local
freopen("input.in", "r", stdin);
#endif
int T; FI(T); while(T--)
run();
Flush;
return 0;
}
I. Leading Robots
假設現在有兩輛車\(i,j\),他們的位置和加速度分別為\(p_i,p_j,a_i,a_j\),不妨\(p_i<p_j\)。
考慮\(i\)追上\(j\)需要的時間,即\(p_2-p_1=\frac{1}{2}a_1t^2-\frac{1}{2}a_2t^2\),那麼變換一下就有\(t^2=-2\frac{p_1-p_2}{a_1-a_2}\)。注意後面部分類似於斜率,所以推導一下維護一個凸包就行。
注意細節,比如\(a_i=a_j,p_i=p_j\)這種情況。
Code
// Author : heyuhhh
// Created Time : 2020/07/22 15:31:28
#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 = 50000 + 5;
int n;
pii a[N];
int q[N], top;
#define FI(n) FastIO::read(n)
#define FO(n) FastIO::write(n)
#define Flush FastIO::Fflush()
namespace FastIO {
const int SIZE = 1 << 16;
char buf[SIZE], obuf[SIZE], str[60];
int bi = SIZE, bn = SIZE, opt;
double D[] = {0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001, 0.0000000001};
int read(char *s) {
while (bn) {
for (; bi < bn && buf[bi] <= ' '; bi++);
if (bi < bn) break;
bn = fread(buf, 1, SIZE, stdin);
bi = 0;
}
int sn = 0;
while (bn) {
for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
if (bi < bn) break;
bn = fread(buf, 1, SIZE, stdin);
bi = 0;
}
s[sn] = 0;
return sn;
}
bool read(int& x) {
int n = read(str), bf = 0;
if (!n) return 0;
int i = 0; if (str[i] == '-') bf = 1, i++; else if (str[i] == '+') i++;
for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
if (bf) x = -x;
return 1;
}
bool read(long long& x) {
int n = read(str), bf;
if (!n) return 0;
int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1;
for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
if (bf < 0) x = -x;
return 1;
}
void write(int x) {
if (x == 0) obuf[opt++] = '0';
else {
if (x < 0) obuf[opt++] = '-', x = -x;
int sn = 0;
while (x) str[sn++] = x % 10 + '0', x /= 10;
for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
}
if (opt >= (SIZE >> 1)) {
fwrite(obuf, 1, opt, stdout);
opt = 0;
}
}
void write(long long x) {
if (x == 0) obuf[opt++] = '0';
else {
if (x < 0) obuf[opt++] = '-', x = -x;
int sn = 0;
while (x) str[sn++] = x % 10 + '0', x /= 10;
for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
}
if (opt >= (SIZE >> 1)) {
fwrite(obuf, 1, opt, stdout);
opt = 0;
}
}
void write(unsigned long long x) {
if (x == 0) obuf[opt++] = '0';
else {
int sn = 0;
while (x) str[sn++] = x % 10 + '0', x /= 10;
for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
}
if (opt >= (SIZE >> 1)) {
fwrite(obuf, 1, opt, stdout);
opt = 0;
}
}
void write(char x) {
obuf[opt++] = x;
if (opt >= (SIZE >> 1)) {
fwrite(obuf, 1, opt, stdout);
opt = 0;
}
}
void Fflush() { if (opt) fwrite(obuf, 1, opt, stdout); opt = 0;}
};
void run() {
FI(n);
for (int i = 1; i <= n; i++) {
FI(a[i].fi), FI(a[i].se);
}
a[n + 1] = MP(0, 0);
sort(a + 1, a + n + 1, [&](pii A, pii B) {
if (A.fi == B.fi) return A.se > B.se;
return A.fi > B.fi;
});
top = 0;
for (int i = 1; i <= n; i++) {
if (a[i] == a[i - 1]) continue;
if (top && a[i].fi <= a[q[top]].fi && a[i].se <= a[q[top]].se) continue;
while (top >= 2 && 1ll * (a[q[top - 1]].fi - a[q[top]].fi) * (a[q[top]].se - a[i].se)
<= 1ll * (a[q[top]].fi - a[i].fi) * (a[q[top - 1]].se - a[q[top]].se)) --top;
q[++top] = i;
}
int ans = top;
// 點重合的情況都不會計算入答案
for (int i = 1; i <= top; i++) {
int x = q[i];
if (a[x] == a[x - 1] || a[x] == a[x + 1]) {
--ans;
}
}
FO(ans), FO('\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; FI(T); while(T--)
run();
Flush;
return 0;
}
K. Minimum Index
前置知識:lydon分解。
那麼答案就相當於每個字元作為結尾的最後一個lydon串的開頭位置。
所以可以遞推一下來求比較方便。
細節見程式碼:
Code
// Author : heyuhhh
// Created Time : 2020/07/22 18:51:06
#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 = 1e5 + 5, MOD = 1e9 + 7;
void run() {
string s;
cin >> s;
int n = s.length();
vector<bool> chk(n);
vector<int> d(n);
d[0] = 1;
int i = 0;
while (i < n) {
int j = i + 1, k = i;
int p = 0;
while (j < n && s[k] <= s[j]) {
if (s[k] < s[j]) {
if (!chk[j]) {
d[j] = i + 1;
}
k = i;
p = 0;
} else {
if (!chk[j]) {
d[j] = d[k] + j - k;
}
++k;
}
chk[j] = true;
++j;
++p;
}
while (i <= k) {
i += j - k;
}
if (i == j && j < n && !chk[j]) {
chk[j] = true;
d[j] = d[k] + j - k;
}
}
int ans = 0;
for (int i = n - 1; i >= 0; i--) {
ans = (1ll * ans * 1112 % MOD + d[i]) % MOD;
}
cout << ans << '\n';
}
int main() {
#ifdef Local
freopen("input.in", "r", stdin);
#endif
ios::sync_with_stdio(falsqe);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T; while(T--)
run();
return 0;
}