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\)的情况,类似于\(abcabc...\)这样即可。
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;
}
重要的是自信,一旦有了自信,人就会赢得一切。