Contest Info
Solved | A | B | C | D | E | F | G | H | I | J | K |
---|---|---|---|---|---|---|---|---|---|---|---|
8 / 11 | Ø | - | Ø | O | O | Ø | O | O | O | - | - |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
A. Tokitsukaze, CSL and Palindrome Game
"掷骰子"类问题有个经典结论,假设我们要得到的序列长度为(L),字符集大小为(S)。那么我每次随机在后面添加一个字符,最后得到期望字符串(t)的期望次数为:
其中(a_i)表示([1,cdots,i])是否为(t)串的border。
知道这个结论过后接下来就相当于比较给定两个串的(a_i)序列的字典序大小。
由于多组询问并且没有长度总和限制,就不能直接进行比较。
现在又有一个结论,一个字符串的border序列能被划分为logn段等差数列。
又由于palindrome border这套理论,一个串的最长回文后缀也是其一个border。由于这个题是回文串,那么把回文树建出来,一个字符串的最长回文后缀被划分为了logn段等差数列。那么我们直接在回文树上比较logn次就行。
细节见代码:
Code
// Author : heyuhhh
// Created Time : 2020/07/31 11:10:13
#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
//head
const int N = 1e5 + 5;
namespace PAM{
int ch[N][26], fail[N], len[N], st[N], cnt[N];
int slink[N], diff[N];
int val[N];
int sz, n, last;
// 0: len=0 1: len=-1
int New(int l, int f) {
memset(ch[++sz], 0, sizeof(ch[sz]));
len[sz] = l, fail[sz] = f;
diff[sz] = slink[sz] = 0;
return sz;
}
void init() {
sz = -1;
New(0, 1); last = New(-1, 0);
st[n = 0] = -1;
memset(cnt, 0, sizeof(cnt));
}
int getf(int x) {
while(st[n - len[x] - 1] != st[n]) x = fail[x];
return x;
}
bool Insert(int c, int i) { //int
st[++n] = c;
int x = getf(last);
bool F = 0;
if(!ch[x][c]) {
F = 1;
int f = getf(fail[x]);
int now;
now = ch[x][c] = New(len[x] + 2, ch[f][c]);
diff[now] = len[now] - len[fail[now]];
if (diff[now] == diff[fail[now]]) slink[now] = slink[fail[now]];
else slink[now] = fail[now];
}
last = ch[x][c];
val[i] = last;
cnt[last]++;
return F;
}
int f[N][20];
void build() {
for (int i = 0; i <= sz; i++) {
f[i][0] = fail[i];
}
for (int j = 1; j < 20; j++) {
for (int i = 0; i <= sz; i++) {
f[i][j] = f[f[i][j - 1]][j - 1];
}
}
}
int find(int x, int l) {
x = val[x];
for (int i = 19; i >= 0; i--) {
if (len[f[x][i]] >= l) {
x = f[x][i];
}
}
return x;
}
int cmp(int u, int v) {
while (u > 1 && v > 1) {
if (len[u] != len[v]) {
return len[u] > len[v] ? 1 : -1;
}
if (diff[u] != diff[v]) {
return diff[u] < diff[v] ? 1 : -1;
}
if (len[u] - len[slink[u]] != len[v] - len[slink[v]]) {
if (len[u] - len[slink[u]] > len[v] - len[slink[v]]) {
return diff[slink[v]] > diff[u] ? 1 : -1;
} else {
return diff[slink[u]] > diff[v] ? -1 : 1;
}
}
u = slink[u], v = slink[v];
}
if (u <= 1 && v <= 1) return 0;
return u > v ? 1 : -1;
}
};
void run() {
PAM::init();
int n;
cin >> n;
string s;
cin >> s;
for (int i = 0; i < n; i++) {
PAM::Insert(s[i] - 'a', i);
}
PAM::build();
int q;
cin >> q;
while (q--) {
int a, b, c, d;
cin >> a >> b >> c >> d;
--a, --b, --c, --d;
a = PAM::find(b, b - a + 1);
b = PAM::find(d, d - c + 1);
int cmp = PAM::cmp(a, b);
if (cmp == -1) {
cout << "sjfnb" << '
';
} else if (cmp == 1) {
cout << "cslnb" << '
';
} else {
cout << "draw" << '
';
}
}
}
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;
}
C. Tokitsukaze and Colorful Tree
题意:
给定一个(n)个结点的树,每个结点有两个属性:颜色和权值。然后有(q)次修改操作,要么修改颜色,要么修改权值。
问每次修改操作过后的答案为多少,答案计算方法为:
思路:
显然可以对每种颜色单独考虑,然后将异或拆位计算,我们只需要一位一位单独考虑,那么接下来只需要处理有多少个结点为(0,1)对并且不互相为祖先就行。
对于某个结点,显然要排除子树内的结点,和到根节点链上的结点。子树内就是一个区间问题,链的话可以直接树剖来解决。直接这样做复杂度貌似是三个log。
这里树剖其实可以省去,我们只需要修改链中的结点时,给其子树的结点打上贡献标记即可,这里相当于区间修改、单点查询,差分一下即可。那么对于一个结点一个是子树内的贡献,另一个是链上结点给他的贡献。
那么此时时间复杂度应该是两个log了,因为还要对每种颜色动态开个线段树,但这样做的话常数可能会比较大。所以我们直接离线对每种颜色处理即可,并且对每种操作增添一个“添加/删除”标记,写起来比较方便。
全程用树状数组,跑得挺快的。
详见代码:
Code
// Author : heyuhhh
// Created Time : 2020/07/29 15:30:54
#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;
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
#define FI(x) FastIO::read(x)
#define FO(x) FastIO::write(x)
#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;}
};
struct BIT {
int c[N];
int lowbit(int x) {
return x & (-x);
}
void add(int x, int v) {
for (; x < N; x += lowbit(x)) {
c[x] += v;
}
}
int query(int x) {
int res = 0;
for (;x > 0; x -= lowbit(x)) {
res += c[x];
}
return res;
}
int query(int l, int r) {
return query(r) - query(l - 1);
}
}A[2], B[2];
struct node {
int id, u, val, t;
};
int n;
vector<int> G[N];
vector<node> v[N];
int col[N], val[N];
int in[N], out[N], T;
ll ans[N];
void init() {
for (int i = 1; i <= n; i++) {
G[i].clear();
v[i].clear();
}
T = 0;
}
void dfs(int u, int fa) {
in[u] = ++T;
for (auto v : G[u]) {
if (v != fa) {
dfs(v, u);
}
}
out[u] = T;
}
void work(int color) {
for (int bit = 0; bit < 20; bit++) {
for (auto it : v[color]) {
int u = it.u, id = it.id;
int b = (it.val >> bit & 1);
vector<int> num(2);
num[0] = A[0].query(1, n) - (A[0].query(in[u], out[u]) + B[0].query(in[u]));
num[1] = A[1].query(1, n) - (A[1].query(in[u], out[u]) + B[1].query(in[u]));
// dbg(color, bit, num[0], num[1]);
ans[id] += 1ll * num[b ^ 1] * (1 << bit) * it.t;
A[b].add(in[u], it.t);
B[b].add(in[u] + 1, it.t);
B[b].add(out[u] + 1, -it.t);
}
}
}
void run() {
FI(n);
init();
for (int i = 1; i <= n; i++) {
FI(col[i]);
}
for (int i = 1; i <= n; i++) {
FI(val[i]);
}
for (int i = 1; i <= n; i++) {
v[col[i]].emplace_back(node{0, i, val[i], 1});
}
for (int i = 1; i < n; i++) {
int u, v;
FI(u), FI(v);
G[u].emplace_back(v);
G[v].emplace_back(u);
}
dfs(1, 0);
int q; FI(q);
for (int i = 1; i <= q; i++) {
int op, x, y;
FI(op), FI(x), FI(y);
v[col[x]].emplace_back(node{i, x, val[x], -1});
if (op == 1) {
val[x] = y;
} else {
col[x] = y;
}
v[col[x]].emplace_back(node{i, x, val[x], 1});
}
for (int i = 1; i <= n; i++) {
v[col[i]].emplace_back(node{q + 1, i, val[i], -1});
}
for (int i = 1; i <= n; i++) {
work(i);
}
for (int i = 1; i <= q; i++) {
ans[i] += ans[i - 1];
}
for (int i = 0; i <= q; i++) {
FO(ans[i]), FO('
');
ans[i] = 0;
}
}
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;
}
D. Tokitsukaze and Multiple
将问题转化为合并任意一段区间使得最终尽可能多的数的和为(p)的倍数。所以直接前缀和维护一下就行。
Code
// Author : heyuhhh
// Created Time : 2020/07/28 12:10:14
#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;
void run() {
int n, p;
cin >> n >> p;
vector<int> a(n + 1);
vector<int> sum(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] %= p;
}
for (int i = 1; i <= n; i++) {
sum[i] = (sum[i - 1] + a[i]) % p;
}
vector<int> f(n + 1);
vector<int> last(p, -1);
last[0] = 0;
for (int i = 1; i <= n; i++) {
f[i] = f[i - 1];
if (last[sum[i]] != -1) {
f[i] = max(f[i], f[last[sum[i]]] + 1);
}
last[sum[i]] = i;
}
cout << f[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;
}
E. Little W and Contest
并查集瞎维护一下即可。
每次连边考虑减去不合法的情况。
Code
// Author : heyuhhh
// Created Time : 2020/07/28 14:04:45
#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;
void run() {
string s;
cin >> s;
int n = s.length();
int sum = 0;
int Min = n + 1;
for (int i = 0; i < n; i++) {
if (s[i] == ')') --sum;
if (s[i] == '(') ++sum;
Min = min(Min, sum);
}
if (Min < 0) {
for (int i = 0; i < n && Min < 0; i++) {
if (s[i] == '*') {
s[i] = '(';
++Min;
}
}
}
if (Min < 0) {
cout << "No solution!" << '
';
return;
}
sum = 0;
for (int i = 0; i < n; i++) {
if (s[i] == ')') --sum;
if (s[i] == '(') ++sum;
}
for (int i = n - 1; i >= 0 && sum > 0; i--) {
if (s[i] == '*') {
s[i] = ')';
--sum;
}
}
sum = 0;
Min = n + 1;
for (int i = 0; i < n; i++) {
if (s[i] == ')') --sum;
if (s[i] == '(') ++sum;
Min = min(Min, sum);
}
if (sum != 0 || Min < 0) {
cout << "No solution!" << '
';
return;
}
string res = "";
for (int i = 0; i < n; i++) {
if (s[i] != '*') res += s[i];
}
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);
int T; cin >> T; while(T--)
run();
return 0;
}
F. X Number
题意:
询问([l,r])区间中,数字(d)出现次数最多的数的个数为多少。
(1leq Tleq 1000,0leq dleq9)。
思路:
这种很显然思路会往数位dp方向靠。但这个题和一般的数位dp不同的是数位个数很少。
数位dp的本质就是枚举位数所有情况,对于达到上限的就继续往下考虑,对于没达到上限的记忆化搜索。因为往往状态是有限个,所以复杂度一般是(O(数位*转移数*状态数))。
但其实记忆化搜索的部分很灵活,只要我们能对当前“任意选”的情况计算出答案即可。比如我们可以使用组合计数那套或者其它类似dp都行。
回到这个题,因为数位很少,我们可以直接枚举出所有情况,即最大相等前缀以及后面一个数的大小,那么剩下的数可以任意取。因为前面(d)的个数已经固定,那么我们就知道后面(d)和其它的应该出现多少次。直接背包dp统计后面部分即可。
具体是枚举最后的最大数量(x),那么(d)出现的次数要达到(x),但是其余的最多只能到(x-1)。我们用(dp[i][j])表示前(i)个数确定了(j)个的合法方案数。剩下的就是对于每个数枚举其出现的次数然后组合数乘一乘就行。
注意前导(0)的情况需要特殊处理一下。
Code
// Author : heyuhhh
// Created Time : 2020/07/28 18:32:04
#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
//head
const int N = 20;
int a[N], tot;
ll C[N][N];
void init() {
C[0][0] = 1;
for (int i = 1; i < N; i++) {
C[i][0] = 1;
for (int j = 1; j <= i; j++) {
C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
}
}
}
ll calc(int s, vector<int>& cnt, int d, int lim, int t = tot) {
if (lim) {
if (s > t) return 0;
ll res = 0;
for (int i = 1; i < 10; i++) {
++cnt[i];
res += calc(s + 1, cnt, d, 0);
--cnt[i];
}
return res;
}
int now = cnt[d];
int Max = 0;
for (int i = 0; i < 10; i++) {
if (i != d) Max = max(Max, cnt[i]);
}
int len = t - s + 1;
if (len <= 0) {
return Max < now;
}
ll res = 0;
for (int x = max(now, Max + 1); x <= tot; x++) {
vector<ll> f(len + 1);
int t = x - now;
if (t > len) continue;
f[t] = C[len][t];
for (int k = 0; k < 10; k++) {
if (k == d) continue;
for (int i = len; i > t; i--) {
for (int j = t; j < i; j++) if (f[j] != 0) {
if (cnt[k] + i - j >= x) continue;
f[i] += C[len - j][i - j] * f[j];
}
}
}
res += f[len];
}
return res;
}
ll calc(ll x, int d) {
tot = 0;
ll t = x;
while (t) {
a[++tot] = t % 10;
t /= 10;
}
reverse(a + 1, a + tot + 1);
ll res = 0;
for (int i = 1; i <= tot; i++) {
vector<int> cnt(10);
for (int j = 1; j < i; j++) {
++cnt[a[j]];
}
// 1 ~ i - 1匹配
if (i == 1) {
// 前导0
for (int k = i + 1; k <= tot; k++) {
res += calc(k, cnt, d, 1);
}
}
int down = (i == 1 ? 1 : 0);
int up = (i == tot ? 0 : 1);
for (int j = down; j <= a[i] - up; j++) {
++cnt[j];
res += calc(i + 1, cnt, d, 0);
--cnt[j];
}
}
return res;
}
void run() {
ll l, r;
int d;
cin >> l >> r >> d;
ll ans = calc(r, d) - calc(l - 1, d);
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);
init();
int T; cin >> T; while(T--)
run();
return 0;
}
G. Tokitsukaze and Rescue
因为数据随机,所以最短路径长度期望不会很长,那么直接暴力找第(k)大最短路即可。
即每次枚举最短路上的边然后删去继续找最短路...
Code
#include<iostream>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 57
typedef pair<int,int> pii;
int n,k;
int G[MAXN][MAXN];
int d[MAXN];
bool boom[MAXN][MAXN];
bool v[MAXN];
int fa[MAXN];
pii road[7][MAXN]; int roadn[7];
void dijkstra(pii *road, int&roadn) {
const int o=1, t=n;
memset(d,0x3f,sizeof d);
memset(v,0,sizeof v);
d[o]=0; fa[o]=-1;
for(int i=1; i<n; i++) {
int x=-1;
for(int j=1; j<=n; j++) {
if(!v[j] && (x==-1 || d[j]<d[x])) x=j;
}
v[x]=1;
for(int y=1; y<=n; y++) if(!boom[x][y]) {
int nd=d[x]+G[x][y];
if(nd<d[y]) {
d[y]=nd;
fa[y]=x;
}
}
}
int cnt=0;
for(int i=t; ~fa[i]; i=fa[i], cnt++, road++) {
road->first=i, road->second=fa[i];
}
roadn=cnt;
}
int ans;
void dfs(int di) {
if(di==k) {
dijkstra(road[di],roadn[di]);
ans=max(ans, d[n]);
return;
}
dijkstra(road[di], roadn[di]);
for(int i=0; i<roadn[di]; i++) {
boom[road[di][i].first][road[di][i].second]=1;
boom[road[di][i].second][road[di][i].first]=1;
dfs(di+1);
boom[road[di][i].first][road[di][i].second]=0;
boom[road[di][i].second][road[di][i].first]=0;
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cout<<fixed<<setprecision(10);
int T; cin>>T;
while(0<T--) {
memset(boom,0,sizeof boom);
ans=0;
cin>>n>>k;
for(int i=0; i<n; i++) {
for(int j=i+1; j<n; j++) {
int u,v,w; cin>>u>>v>>w;
G[u][v]=G[v][u]=w;
}
}
dfs(0);
cout<<ans<<'
';
}
}
H. Triangle Collision
队友写的。
Code
#include<iostream>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
inline long double cross(long double x1, long double x2, long double y1, long double y2) {
return x1*y2-x2*y1;
}
#define EPS 1e-6
int dcmp(long double x) {return (x>EPS)-(x<-EPS);}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cout<<fixed<<setprecision(10);
int T; cin>>T;
while(0<T--) {
int L,vx,vy;
long double x,y,L3,xx,yy,zz,vxx,vyy,vzz,t1,t2,t3,dt1,dt2,dt3;
int k;
cin>>L>>x>>y>>vx>>vy>>k;
x+=L/2.0l;
L3=L/sqrtl(2.0l);
xx=x-1.0l/sqrtl(3.0l)*y, yy=2.0l/sqrtl(3.0l)*y;
zz=cross(-xx,L-yy,L-xx,-yy)/L3/2;
vxx=vx-1.0l/sqrtl(3.0l)*vy, vyy=2.0l/sqrtl(3.0l)*vy;
vzz=cross(vxx,vyy,-1,1)/sqrtl(2.0l);
t1=abs(L/vyy), t2=abs(L/vxx), t3=abs(L3/vzz);
#define vx none
#define vy none
#define vz none
if(dcmp(vxx)<0) dt2=xx/-vxx;
else if(dcmp(vxx)>0) dt2=(L-xx)/vxx;
if(dcmp(vyy)<0) dt1=yy/-vyy;
else if(dcmp(vyy)>0) dt1=(L-yy)/vyy;
if(dcmp(vzz)<0) dt3=(L3+zz)/-vzz;
else if(dcmp(vzz)>0) dt3=-zz/vzz;
#define L fadsfsa
long double L=0, R=1e11;
while((R-L)>1e-5) {
long double M=L+(R-L)/2;
long long cnt=0;
if(dcmp(vyy)!=0 && dcmp(M-dt1)>=0) {
cnt++;
cnt+=(long long)(floor((M-dt1)/t1)+0.1);
}
if(dcmp(vxx)!=0 && dcmp(M-dt2)>=0) {
cnt++;
cnt+=(long long)(floor((M-dt2)/t2)+0.1);
}
if(dcmp(vzz)!=0 && dcmp(M-dt3)>=0) {
cnt++;
cnt+=(long long)(floor((M-dt3)/t3)+0.1);
}
if(cnt>=k) R=M;
else L=M;
}
cout<<L<<'
';
}
}
I. Parentheses Matching
贪心。
Code
// Author : heyuhhh
// Created Time : 2020/07/28 14:04:45
#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;
void run() {
string s;
cin >> s;
int n = s.length();
int sum = 0;
int Min = n + 1;
for (int i = 0; i < n; i++) {
if (s[i] == ')') --sum;
if (s[i] == '(') ++sum;
Min = min(Min, sum);
}
if (Min < 0) {
for (int i = 0; i < n && Min < 0; i++) {
if (s[i] == '*') {
s[i] = '(';
++Min;
}
}
}
if (Min < 0) {
cout << "No solution!" << '
';
return;
}
sum = 0;
for (int i = 0; i < n; i++) {
if (s[i] == ')') --sum;
if (s[i] == '(') ++sum;
}
for (int i = n - 1; i >= 0 && sum > 0; i--) {
if (s[i] == '*') {
s[i] = ')';
--sum;
}
}
sum = 0;
Min = n + 1;
for (int i = 0; i < n; i++) {
if (s[i] == ')') --sum;
if (s[i] == '(') ++sum;
Min = min(Min, sum);
}
if (sum != 0 || Min < 0) {
cout << "No solution!" << '
';
return;
}
string res = "";
for (int i = 0; i < n; i++) {
if (s[i] != '*') res += s[i];
}
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);
int T; cin >> T; while(T--)
run();
return 0;
}