A – 小凯的疑惑
送命规律题。当然也可以考虑用 exgcd 的性质,以下是感性理解:
考虑设这个数为\(x \equiv ya {\pmod b}\),展开就是:
\[ x = ya + kb, k \in [1, b – 1] \]
发现\(k \geq 0\)时都满足,那么反过来取\(-1\)就可以又满足最大又满足不满足条件。
// P3951.cpp
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
unsigned long long a, b, i;
cin >> a >> b;
cout << a * b - a - b;
return 0;
}
// P3951.cpp
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
unsigned long long a, b, i;
cin >> a >> b;
cout << a * b - a - b;
return 0;
}
// P3951.cpp #include <iostream> #include <cstring> using namespace std; int main() { unsigned long long a, b, i; cin >> a >> b; cout << a * b - a - b; return 0; }
B – 时间复杂度
刚开始我觉得这道题目非常的可怕,最后我还是自己写了出来(因为题目给的格式还是很好的,没有想象中的困难)。用计数器记录次数、是否零次循环即可。
// P3952.cpp
#include <bits/stdc++.h>
using namespace std;
char content[1010], opt[20];
int T, L, complexity, vis[300];
struct instruction
{
char typ, var_name[3];
bool tag, tag2;
int x, y;
instruction()
{
typ = 0, memset(var_name, 0, sizeof(var_name));
tag = tag2 = false;
x = y = 0;
}
};
stack<instruction> st;
int read()
{
int pos = 1, ret = 0;
while (opt[pos] != 0)
ret = ret * 10 + opt[pos] - '0', pos++;
return ret;
}
int main()
{
scanf("%d", &T);
while (T--)
{
memset(vis, 0, sizeof(vis));
// complexity reader;
complexity = 0;
memset(opt, 0, sizeof(opt));
scanf("%d%s", &L, opt + 1);
if (strlen(opt + 1) == 4)
complexity = (opt[3] == '1') ? 0 : 1;
else
for (int i = 5, siz = strlen(opt + 1); i <= siz - 1; i++)
complexity = complexity * 10 + (opt[i] - '0');
// read the whole content;
int mx_idx = 0;
bool err_flag = false;
while (!st.empty())
st.pop();
for (int i = 1, curt_complexity = 0, choke = 0; i <= L; i++)
{
instruction ist;
ist.tag = false, ist.tag2 = false;
scanf("%s", content + 1);
ist.typ = content[1];
if (ist.typ == 'F')
{
scanf("%s", ist.var_name + 1);
// repeated name;
err_flag |= (vis[ist.var_name[1]] > 0);
vis[ist.var_name[1]]++;
// read the condition;
scanf("%s", opt + 1);
if (opt[1] == 'n')
ist.x = -1;
else
ist.x = read();
scanf("%s", opt + 1);
if (opt[1] == 'n')
ist.y = -1;
else
ist.y = read();
if (ist.x != -1 && ist.y == -1)
{
// O(n);
if (choke == 0)
curt_complexity++, ist.tag2 = true;
}
else if (ist.x == -1 && ist.y != -1)
choke++, ist.tag = true;
else if (ist.x != -1 && ist.y != -1 && ist.x > ist.y)
choke++, ist.tag = true;
st.push(ist);
}
else if (ist.typ == 'E')
{
if (st.empty())
// nowhere to go;
err_flag = true;
else
{
instruction current_ist = st.top();
if (current_ist.tag)
choke--;
if (current_ist.tag2)
curt_complexity--;
vis[current_ist.var_name[1]]--;
st.pop();
}
}
mx_idx = max(mx_idx, curt_complexity);
}
err_flag |= (!st.empty());
if (err_flag)
{
puts("ERR");
continue;
}
puts(mx_idx == complexity ? "Yes" : "No");
}
return 0;
}
// P3952.cpp
#include <bits/stdc++.h>
using namespace std;
char content[1010], opt[20];
int T, L, complexity, vis[300];
struct instruction
{
char typ, var_name[3];
bool tag, tag2;
int x, y;
instruction()
{
typ = 0, memset(var_name, 0, sizeof(var_name));
tag = tag2 = false;
x = y = 0;
}
};
stack<instruction> st;
int read()
{
int pos = 1, ret = 0;
while (opt[pos] != 0)
ret = ret * 10 + opt[pos] - '0', pos++;
return ret;
}
int main()
{
scanf("%d", &T);
while (T--)
{
memset(vis, 0, sizeof(vis));
// complexity reader;
complexity = 0;
memset(opt, 0, sizeof(opt));
scanf("%d%s", &L, opt + 1);
if (strlen(opt + 1) == 4)
complexity = (opt[3] == '1') ? 0 : 1;
else
for (int i = 5, siz = strlen(opt + 1); i <= siz - 1; i++)
complexity = complexity * 10 + (opt[i] - '0');
// read the whole content;
int mx_idx = 0;
bool err_flag = false;
while (!st.empty())
st.pop();
for (int i = 1, curt_complexity = 0, choke = 0; i <= L; i++)
{
instruction ist;
ist.tag = false, ist.tag2 = false;
scanf("%s", content + 1);
ist.typ = content[1];
if (ist.typ == 'F')
{
scanf("%s", ist.var_name + 1);
// repeated name;
err_flag |= (vis[ist.var_name[1]] > 0);
vis[ist.var_name[1]]++;
// read the condition;
scanf("%s", opt + 1);
if (opt[1] == 'n')
ist.x = -1;
else
ist.x = read();
scanf("%s", opt + 1);
if (opt[1] == 'n')
ist.y = -1;
else
ist.y = read();
if (ist.x != -1 && ist.y == -1)
{
// O(n);
if (choke == 0)
curt_complexity++, ist.tag2 = true;
}
else if (ist.x == -1 && ist.y != -1)
choke++, ist.tag = true;
else if (ist.x != -1 && ist.y != -1 && ist.x > ist.y)
choke++, ist.tag = true;
st.push(ist);
}
else if (ist.typ == 'E')
{
if (st.empty())
// nowhere to go;
err_flag = true;
else
{
instruction current_ist = st.top();
if (current_ist.tag)
choke--;
if (current_ist.tag2)
curt_complexity--;
vis[current_ist.var_name[1]]--;
st.pop();
}
}
mx_idx = max(mx_idx, curt_complexity);
}
err_flag |= (!st.empty());
if (err_flag)
{
puts("ERR");
continue;
}
puts(mx_idx == complexity ? "Yes" : "No");
}
return 0;
}
// P3952.cpp #include <bits/stdc++.h> using namespace std; char content[1010], opt[20]; int T, L, complexity, vis[300]; struct instruction { char typ, var_name[3]; bool tag, tag2; int x, y; instruction() { typ = 0, memset(var_name, 0, sizeof(var_name)); tag = tag2 = false; x = y = 0; } }; stack<instruction> st; int read() { int pos = 1, ret = 0; while (opt[pos] != 0) ret = ret * 10 + opt[pos] - '0', pos++; return ret; } int main() { scanf("%d", &T); while (T--) { memset(vis, 0, sizeof(vis)); // complexity reader; complexity = 0; memset(opt, 0, sizeof(opt)); scanf("%d%s", &L, opt + 1); if (strlen(opt + 1) == 4) complexity = (opt[3] == '1') ? 0 : 1; else for (int i = 5, siz = strlen(opt + 1); i <= siz - 1; i++) complexity = complexity * 10 + (opt[i] - '0'); // read the whole content; int mx_idx = 0; bool err_flag = false; while (!st.empty()) st.pop(); for (int i = 1, curt_complexity = 0, choke = 0; i <= L; i++) { instruction ist; ist.tag = false, ist.tag2 = false; scanf("%s", content + 1); ist.typ = content[1]; if (ist.typ == 'F') { scanf("%s", ist.var_name + 1); // repeated name; err_flag |= (vis[ist.var_name[1]] > 0); vis[ist.var_name[1]]++; // read the condition; scanf("%s", opt + 1); if (opt[1] == 'n') ist.x = -1; else ist.x = read(); scanf("%s", opt + 1); if (opt[1] == 'n') ist.y = -1; else ist.y = read(); if (ist.x != -1 && ist.y == -1) { // O(n); if (choke == 0) curt_complexity++, ist.tag2 = true; } else if (ist.x == -1 && ist.y != -1) choke++, ist.tag = true; else if (ist.x != -1 && ist.y != -1 && ist.x > ist.y) choke++, ist.tag = true; st.push(ist); } else if (ist.typ == 'E') { if (st.empty()) // nowhere to go; err_flag = true; else { instruction current_ist = st.top(); if (current_ist.tag) choke--; if (current_ist.tag2) curt_complexity--; vis[current_ist.var_name[1]]--; st.pop(); } } mx_idx = max(mx_idx, curt_complexity); } err_flag |= (!st.empty()); if (err_flag) { puts("ERR"); continue; } puts(mx_idx == complexity ? "Yes" : "No"); } return 0; }
C – 逛公园
策策主任逛机房。
这道题看上去超级难,但是最后用记忆化搜索的方式暴解起初让我意外,但是过了几秒之后真的觉得很妙。因为\(k < 50\),显然可以直接记忆化搜索状态进行转移(管他妈的转移顺序)。
设置状态\(dp[u][addition]\),其中\(addition\)代表的就是剩下的\(bonus\)成分,然后就可以开始暴力计数了。这个方法是真的好。
// P3953.cpp
#include <bits/stdc++.h>
#define ll long long
#define pr pair<ll, int>
using namespace std;
const int MAX_N = 100100, MAX_E = 200010;
int head[MAX_N], n, m, k, p, current, T;
ll dist[MAX_N], dp[MAX_N][60];
bool vis[MAX_N], inst[MAX_N][60];
struct edge
{
int to, nxt;
ll weight;
bool tag;
} edges[MAX_E << 1];
void addpath(int src, int dst, ll weight, bool toggle)
{
edges[current].to = dst, edges[current].nxt = head[src];
edges[current].tag = toggle, edges[current].weight = weight;
head[src] = current++;
}
void shortest_path()
{
memset(dist, 0x3f, sizeof(dist));
memset(vis, false, sizeof(vis));
priority_queue<pr> pq;
pq.push(make_pair(0, n)), dist[n] = 0;
while (!pq.empty())
{
int u = pq.top().second;
pq.pop();
if (vis[u])
continue;
vis[u] = true;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (edges[i].tag == true && dist[edges[i].to] > dist[u] + edges[i].weight)
dist[edges[i].to] = dist[u] + edges[i].weight, pq.push(make_pair(-dist[edges[i].to], edges[i].to));
}
}
int dfs(int u, int addition)
{
if (inst[u][addition])
return -1;
if (dp[u][addition])
return dp[u][addition];
inst[u][addition] = true;
if (u == n)
dp[u][addition] = 1;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (dist[edges[i].to] - dist[u] + edges[i].weight <= addition && edges[i].tag == true)
{
ll diff = dist[edges[i].to] - dist[u] + edges[i].weight;
if (dfs(edges[i].to, addition - diff) == -1)
return (dp[u][addition] = -1);
dp[u][addition] = (1LL * dp[u][addition] + 1LL * dp[edges[i].to][addition - diff]) % p;
}
inst[u][addition] = false;
return dp[u][addition];
}
int main()
{
scanf("%d", &T);
while (T--)
{
memset(head, -1, sizeof(head)), current = 0;
memset(inst, 0, sizeof(inst)), memset(dp, 0, sizeof(dp));
scanf("%d%d%d%d", &n, &m, &k, &p);
for (int i = 1, u, v, w; i <= m; i++)
scanf("%d%d%d", &u, &v, &w), addpath(u, v, w, false), addpath(v, u, w, true);
shortest_path();
for (int i = 0; i < current; i++)
edges[i].tag ^= 1;
printf("%d\n", dfs(1, k));
}
return 0;
}
// P3953.cpp
#include <bits/stdc++.h>
#define ll long long
#define pr pair<ll, int>
using namespace std;
const int MAX_N = 100100, MAX_E = 200010;
int head[MAX_N], n, m, k, p, current, T;
ll dist[MAX_N], dp[MAX_N][60];
bool vis[MAX_N], inst[MAX_N][60];
struct edge
{
int to, nxt;
ll weight;
bool tag;
} edges[MAX_E << 1];
void addpath(int src, int dst, ll weight, bool toggle)
{
edges[current].to = dst, edges[current].nxt = head[src];
edges[current].tag = toggle, edges[current].weight = weight;
head[src] = current++;
}
void shortest_path()
{
memset(dist, 0x3f, sizeof(dist));
memset(vis, false, sizeof(vis));
priority_queue<pr> pq;
pq.push(make_pair(0, n)), dist[n] = 0;
while (!pq.empty())
{
int u = pq.top().second;
pq.pop();
if (vis[u])
continue;
vis[u] = true;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (edges[i].tag == true && dist[edges[i].to] > dist[u] + edges[i].weight)
dist[edges[i].to] = dist[u] + edges[i].weight, pq.push(make_pair(-dist[edges[i].to], edges[i].to));
}
}
int dfs(int u, int addition)
{
if (inst[u][addition])
return -1;
if (dp[u][addition])
return dp[u][addition];
inst[u][addition] = true;
if (u == n)
dp[u][addition] = 1;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (dist[edges[i].to] - dist[u] + edges[i].weight <= addition && edges[i].tag == true)
{
ll diff = dist[edges[i].to] - dist[u] + edges[i].weight;
if (dfs(edges[i].to, addition - diff) == -1)
return (dp[u][addition] = -1);
dp[u][addition] = (1LL * dp[u][addition] + 1LL * dp[edges[i].to][addition - diff]) % p;
}
inst[u][addition] = false;
return dp[u][addition];
}
int main()
{
scanf("%d", &T);
while (T--)
{
memset(head, -1, sizeof(head)), current = 0;
memset(inst, 0, sizeof(inst)), memset(dp, 0, sizeof(dp));
scanf("%d%d%d%d", &n, &m, &k, &p);
for (int i = 1, u, v, w; i <= m; i++)
scanf("%d%d%d", &u, &v, &w), addpath(u, v, w, false), addpath(v, u, w, true);
shortest_path();
for (int i = 0; i < current; i++)
edges[i].tag ^= 1;
printf("%d\n", dfs(1, k));
}
return 0;
}
// P3953.cpp #include <bits/stdc++.h> #define ll long long #define pr pair<ll, int> using namespace std; const int MAX_N = 100100, MAX_E = 200010; int head[MAX_N], n, m, k, p, current, T; ll dist[MAX_N], dp[MAX_N][60]; bool vis[MAX_N], inst[MAX_N][60]; struct edge { int to, nxt; ll weight; bool tag; } edges[MAX_E << 1]; void addpath(int src, int dst, ll weight, bool toggle) { edges[current].to = dst, edges[current].nxt = head[src]; edges[current].tag = toggle, edges[current].weight = weight; head[src] = current++; } void shortest_path() { memset(dist, 0x3f, sizeof(dist)); memset(vis, false, sizeof(vis)); priority_queue<pr> pq; pq.push(make_pair(0, n)), dist[n] = 0; while (!pq.empty()) { int u = pq.top().second; pq.pop(); if (vis[u]) continue; vis[u] = true; for (int i = head[u]; i != -1; i = edges[i].nxt) if (edges[i].tag == true && dist[edges[i].to] > dist[u] + edges[i].weight) dist[edges[i].to] = dist[u] + edges[i].weight, pq.push(make_pair(-dist[edges[i].to], edges[i].to)); } } int dfs(int u, int addition) { if (inst[u][addition]) return -1; if (dp[u][addition]) return dp[u][addition]; inst[u][addition] = true; if (u == n) dp[u][addition] = 1; for (int i = head[u]; i != -1; i = edges[i].nxt) if (dist[edges[i].to] - dist[u] + edges[i].weight <= addition && edges[i].tag == true) { ll diff = dist[edges[i].to] - dist[u] + edges[i].weight; if (dfs(edges[i].to, addition - diff) == -1) return (dp[u][addition] = -1); dp[u][addition] = (1LL * dp[u][addition] + 1LL * dp[edges[i].to][addition - diff]) % p; } inst[u][addition] = false; return dp[u][addition]; } int main() { scanf("%d", &T); while (T--) { memset(head, -1, sizeof(head)), current = 0; memset(inst, 0, sizeof(inst)), memset(dp, 0, sizeof(dp)); scanf("%d%d%d%d", &n, &m, &k, &p); for (int i = 1, u, v, w; i <= m; i++) scanf("%d%d%d", &u, &v, &w), addpath(u, v, w, false), addpath(v, u, w, true); shortest_path(); for (int i = 0; i < current; i++) edges[i].tag ^= 1; printf("%d\n", dfs(1, k)); } return 0; }
D – 奶酪
sb 并查集搞定。
// P3958.cpp
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
#define ll long long
int n, h, r;
struct Point
{
ll x, y, z;
Point() {}
Point(int x, int y, int z)
{
this->x = x;
this->y = y;
this->z = z;
}
};
struct Sphere
{
Point center;
ll radius;
bool upperColliding;
bool lowerColliding;
int index;
Sphere() {}
Sphere(Point c, int radius);
};
double getDist(Point a, Point b);
bool checkCollide(Sphere s1, Sphere s2);
bool checkLowerCollide(Sphere s);
bool checkUpperCollide(Sphere s);
Sphere::Sphere(Point c, int radius)
{
center = c;
this->radius = radius;
}
double getDist(Point a, Point b)
{
return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2) + pow(a.z - b.z, 2));
}
bool checkUpperCollide(Sphere s)
{
if (s.center.z + s.radius >= h)
return true;
return false;
}
bool checkLowerCollide(Sphere s)
{
if (s.center.z - s.radius <= 0)
return true;
return false;
}
bool checkCollide(Sphere s1, Sphere s2)
{
if (getDist(s1.center, s2.center) <= s1.radius + s2.radius)
return true;
return false;
}
struct Batch
{
vector<Sphere> spheres;
vector<Sphere> upper;
vector<Sphere> lower;
int mem[100100];
void MakeHeap()
{
for (int i = 0; i < n + 2; i++)
mem[i] = i;
}
void UnionElement(int p, int q)
{
int p_parent = FindElement(p);
int q_element = FindElement(q);
if (p_parent != q_element)
mem[p_parent] = q_element;
}
int FindElement(int p)
{
if (mem[p] != p)
mem[p] = FindElement(mem[p]);
return mem[p];
}
bool allFlag = true;
bool goFlag = false;
void initialize()
{
cin >> n >> h >> r;
for (int i = 0; i < n; i++)
{
ll x, y, z;
cin >> x >> y >> z;
Sphere sss = Sphere(Point(x, y, z), r);
sss.index = i;
sss.upperColliding = checkUpperCollide(sss);
sss.lowerColliding = checkLowerCollide(sss);
if (sss.upperColliding && sss.lowerColliding)
goFlag = true;
if (sss.upperColliding)
allFlag = false, upper.push_back(sss);
if (sss.lowerColliding)
lower.push_back(sss);
spheres.push_back(sss);
}
return;
}
void preprocess()
{
MakeHeap();
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
if (i == j)
continue;
if (checkCollide(spheres[i], spheres[j]))
UnionElement(i, j);
}
}
void Solve()
{
if (goFlag)
{
cout << "Yes" << endl;
return;
}
if (allFlag)
{
cout << "No" << endl;
return;
}
preprocess();
for (int i = 0; i < upper.size(); i++)
for (int j = 0; j < lower.size(); j++)
{
if (upper[i].index == lower[i].index)
continue;
int resi = FindElement(upper[i].index), resj = FindElement(lower[j].index);
if (resi != resj)
continue;
cout << "Yes" << endl;
return;
}
cout << "No" << endl;
}
};
int main()
{
int T;
cin >> T;
while (T--)
{
Batch b;
b.initialize();
b.Solve();
}
return 0;
}
// P3958.cpp
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
#define ll long long
int n, h, r;
struct Point
{
ll x, y, z;
Point() {}
Point(int x, int y, int z)
{
this->x = x;
this->y = y;
this->z = z;
}
};
struct Sphere
{
Point center;
ll radius;
bool upperColliding;
bool lowerColliding;
int index;
Sphere() {}
Sphere(Point c, int radius);
};
double getDist(Point a, Point b);
bool checkCollide(Sphere s1, Sphere s2);
bool checkLowerCollide(Sphere s);
bool checkUpperCollide(Sphere s);
Sphere::Sphere(Point c, int radius)
{
center = c;
this->radius = radius;
}
double getDist(Point a, Point b)
{
return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2) + pow(a.z - b.z, 2));
}
bool checkUpperCollide(Sphere s)
{
if (s.center.z + s.radius >= h)
return true;
return false;
}
bool checkLowerCollide(Sphere s)
{
if (s.center.z - s.radius <= 0)
return true;
return false;
}
bool checkCollide(Sphere s1, Sphere s2)
{
if (getDist(s1.center, s2.center) <= s1.radius + s2.radius)
return true;
return false;
}
struct Batch
{
vector<Sphere> spheres;
vector<Sphere> upper;
vector<Sphere> lower;
int mem[100100];
void MakeHeap()
{
for (int i = 0; i < n + 2; i++)
mem[i] = i;
}
void UnionElement(int p, int q)
{
int p_parent = FindElement(p);
int q_element = FindElement(q);
if (p_parent != q_element)
mem[p_parent] = q_element;
}
int FindElement(int p)
{
if (mem[p] != p)
mem[p] = FindElement(mem[p]);
return mem[p];
}
bool allFlag = true;
bool goFlag = false;
void initialize()
{
cin >> n >> h >> r;
for (int i = 0; i < n; i++)
{
ll x, y, z;
cin >> x >> y >> z;
Sphere sss = Sphere(Point(x, y, z), r);
sss.index = i;
sss.upperColliding = checkUpperCollide(sss);
sss.lowerColliding = checkLowerCollide(sss);
if (sss.upperColliding && sss.lowerColliding)
goFlag = true;
if (sss.upperColliding)
allFlag = false, upper.push_back(sss);
if (sss.lowerColliding)
lower.push_back(sss);
spheres.push_back(sss);
}
return;
}
void preprocess()
{
MakeHeap();
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
if (i == j)
continue;
if (checkCollide(spheres[i], spheres[j]))
UnionElement(i, j);
}
}
void Solve()
{
if (goFlag)
{
cout << "Yes" << endl;
return;
}
if (allFlag)
{
cout << "No" << endl;
return;
}
preprocess();
for (int i = 0; i < upper.size(); i++)
for (int j = 0; j < lower.size(); j++)
{
if (upper[i].index == lower[i].index)
continue;
int resi = FindElement(upper[i].index), resj = FindElement(lower[j].index);
if (resi != resj)
continue;
cout << "Yes" << endl;
return;
}
cout << "No" << endl;
}
};
int main()
{
int T;
cin >> T;
while (T--)
{
Batch b;
b.initialize();
b.Solve();
}
return 0;
}
// P3958.cpp #include <iostream> #include <vector> #include <cmath> using namespace std; #define ll long long int n, h, r; struct Point { ll x, y, z; Point() {} Point(int x, int y, int z) { this->x = x; this->y = y; this->z = z; } }; struct Sphere { Point center; ll radius; bool upperColliding; bool lowerColliding; int index; Sphere() {} Sphere(Point c, int radius); }; double getDist(Point a, Point b); bool checkCollide(Sphere s1, Sphere s2); bool checkLowerCollide(Sphere s); bool checkUpperCollide(Sphere s); Sphere::Sphere(Point c, int radius) { center = c; this->radius = radius; } double getDist(Point a, Point b) { return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2) + pow(a.z - b.z, 2)); } bool checkUpperCollide(Sphere s) { if (s.center.z + s.radius >= h) return true; return false; } bool checkLowerCollide(Sphere s) { if (s.center.z - s.radius <= 0) return true; return false; } bool checkCollide(Sphere s1, Sphere s2) { if (getDist(s1.center, s2.center) <= s1.radius + s2.radius) return true; return false; } struct Batch { vector<Sphere> spheres; vector<Sphere> upper; vector<Sphere> lower; int mem[100100]; void MakeHeap() { for (int i = 0; i < n + 2; i++) mem[i] = i; } void UnionElement(int p, int q) { int p_parent = FindElement(p); int q_element = FindElement(q); if (p_parent != q_element) mem[p_parent] = q_element; } int FindElement(int p) { if (mem[p] != p) mem[p] = FindElement(mem[p]); return mem[p]; } bool allFlag = true; bool goFlag = false; void initialize() { cin >> n >> h >> r; for (int i = 0; i < n; i++) { ll x, y, z; cin >> x >> y >> z; Sphere sss = Sphere(Point(x, y, z), r); sss.index = i; sss.upperColliding = checkUpperCollide(sss); sss.lowerColliding = checkLowerCollide(sss); if (sss.upperColliding && sss.lowerColliding) goFlag = true; if (sss.upperColliding) allFlag = false, upper.push_back(sss); if (sss.lowerColliding) lower.push_back(sss); spheres.push_back(sss); } return; } void preprocess() { MakeHeap(); for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) { if (i == j) continue; if (checkCollide(spheres[i], spheres[j])) UnionElement(i, j); } } void Solve() { if (goFlag) { cout << "Yes" << endl; return; } if (allFlag) { cout << "No" << endl; return; } preprocess(); for (int i = 0; i < upper.size(); i++) for (int j = 0; j < lower.size(); j++) { if (upper[i].index == lower[i].index) continue; int resi = FindElement(upper[i].index), resj = FindElement(lower[j].index); if (resi != resj) continue; cout << "Yes" << endl; return; } cout << "No" << endl; } }; int main() { int T; cin >> T; while (T--) { Batch b; b.initialize(); b.Solve(); } return 0; }
E – 宝藏
想到了状态之后就算是 sb 题了。设置状态\(dp[stat][i]\),stat 就是已有的点集,\(i\)是最大树高。知道这个之后枚举子集就可以搞定了(因为最大树高为最糟情况,且这个情况会由状态压缩自动处理掉,请自行思考)。
// P3959.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 20, INF = 0x3f3f3f3f;
int dist[MAX_N][MAX_N], n, m, dp[1 << MAX_N][MAX_N], dist_mask[1 << MAX_N];
int main()
{
memset(dist, 0x3f, sizeof(dist));
scanf("%d%d", &n, &m);
for (int i = 1, u, v, w; i <= m; i++)
scanf("%d%d%d", &u, &v, &w), u--, v--, dist[u][v] = dist[v][u] = min(dist[u][v], w);
for (int i = 1; i < (1 << n); i++)
for (int j = 0; j < n; j++)
if (i & (1 << j))
{
dist[j][j] = 0;
for (int k = 0; k < n; k++)
if (dist[j][k] != INF)
dist_mask[i] |= (1 << k);
}
memset(dp, 0x3f, sizeof(dp));
for (int i = 0; i < n; i++)
dp[1 << i][0] = 0;
for (int stat = 2; stat < (1 << n); stat++)
for (int subset = stat - 1; subset; subset = (subset - 1) & stat)
if ((dist_mask[subset] | stat) == dist_mask[subset])
{
int sum = 0, from = subset ^ stat;
for (int k = 0; k < n; k++)
if (from & (1 << k))
{
int tmp = INF;
for (int idx = 0; idx < n; idx++)
if (subset & (1 << idx))
tmp = min(tmp, dist[idx][k]);
sum += tmp;
}
for (int i = 1; i < n; i++)
if (dp[subset][i - 1] != INF)
dp[stat][i] = min(dp[stat][i], sum * i + dp[subset][i - 1]);
}
int ans = INF;
for (int i = 0; i < n; i++)
ans = min(ans, dp[(1 << n) - 1][i]);
printf("%d", ans);
return 0;
}
// P3959.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 20, INF = 0x3f3f3f3f;
int dist[MAX_N][MAX_N], n, m, dp[1 << MAX_N][MAX_N], dist_mask[1 << MAX_N];
int main()
{
memset(dist, 0x3f, sizeof(dist));
scanf("%d%d", &n, &m);
for (int i = 1, u, v, w; i <= m; i++)
scanf("%d%d%d", &u, &v, &w), u--, v--, dist[u][v] = dist[v][u] = min(dist[u][v], w);
for (int i = 1; i < (1 << n); i++)
for (int j = 0; j < n; j++)
if (i & (1 << j))
{
dist[j][j] = 0;
for (int k = 0; k < n; k++)
if (dist[j][k] != INF)
dist_mask[i] |= (1 << k);
}
memset(dp, 0x3f, sizeof(dp));
for (int i = 0; i < n; i++)
dp[1 << i][0] = 0;
for (int stat = 2; stat < (1 << n); stat++)
for (int subset = stat - 1; subset; subset = (subset - 1) & stat)
if ((dist_mask[subset] | stat) == dist_mask[subset])
{
int sum = 0, from = subset ^ stat;
for (int k = 0; k < n; k++)
if (from & (1 << k))
{
int tmp = INF;
for (int idx = 0; idx < n; idx++)
if (subset & (1 << idx))
tmp = min(tmp, dist[idx][k]);
sum += tmp;
}
for (int i = 1; i < n; i++)
if (dp[subset][i - 1] != INF)
dp[stat][i] = min(dp[stat][i], sum * i + dp[subset][i - 1]);
}
int ans = INF;
for (int i = 0; i < n; i++)
ans = min(ans, dp[(1 << n) - 1][i]);
printf("%d", ans);
return 0;
}
// P3959.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 20, INF = 0x3f3f3f3f; int dist[MAX_N][MAX_N], n, m, dp[1 << MAX_N][MAX_N], dist_mask[1 << MAX_N]; int main() { memset(dist, 0x3f, sizeof(dist)); scanf("%d%d", &n, &m); for (int i = 1, u, v, w; i <= m; i++) scanf("%d%d%d", &u, &v, &w), u--, v--, dist[u][v] = dist[v][u] = min(dist[u][v], w); for (int i = 1; i < (1 << n); i++) for (int j = 0; j < n; j++) if (i & (1 << j)) { dist[j][j] = 0; for (int k = 0; k < n; k++) if (dist[j][k] != INF) dist_mask[i] |= (1 << k); } memset(dp, 0x3f, sizeof(dp)); for (int i = 0; i < n; i++) dp[1 << i][0] = 0; for (int stat = 2; stat < (1 << n); stat++) for (int subset = stat - 1; subset; subset = (subset - 1) & stat) if ((dist_mask[subset] | stat) == dist_mask[subset]) { int sum = 0, from = subset ^ stat; for (int k = 0; k < n; k++) if (from & (1 << k)) { int tmp = INF; for (int idx = 0; idx < n; idx++) if (subset & (1 << idx)) tmp = min(tmp, dist[idx][k]); sum += tmp; } for (int i = 1; i < n; i++) if (dp[subset][i - 1] != INF) dp[stat][i] = min(dp[stat][i], sum * i + dp[subset][i - 1]); } int ans = INF; for (int i = 0; i < n; i++) ans = min(ans, dp[(1 << n) - 1][i]); printf("%d", ans); return 0; }
F – 列队
50 分退役题。
首先有一个性质:每一次出队的时候,只会影响当前列和当前行和右下角的格子。所以,不难想到,维护一堆线段树来记录每一列某个位置前有多少个人,这样我们可以用权值线段树那一套,来二分出那个位置(每次多了一个点,加一之后就会自动偏移,非常巧妙)。超过范围的就用 vector 存就好。
当然,即使是这样,我还是不会。
// P3960.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 3e5 + 200, SEG = 1e7 + 200;
ll siz[SEG], n, m, q, ptot, upper;
int lson[SEG], rson[SEG], roots[SEG];
vector<ll> vecs[MAX_N];
ll atRank(ll k, int l, int r, int p)
{
if (l == r)
return l;
ll mid = (l + r) >> 1, lsiz = mid - l + 1 - siz[lson[p]];
if (k <= lsiz)
return atRank(k, l, mid, lson[p]);
else
return atRank(k - lsiz, mid + 1, r, rson[p]);
}
int update(int qx, int l, int r, int p)
{
if (p == 0)
p = ++ptot;
++siz[p];
if (l == r)
return p;
int mid = (l + r) >> 1;
if (qx <= mid)
lson[p] = update(qx, l, mid, lson[p]);
else
rson[p] = update(qx, mid + 1, r, rson[p]);
return p;
}
ll query_col(int x, int y)
{
ll tmp = atRank(y, 1, upper, roots[x]);
roots[x] = update(tmp, 1, upper, roots[x]);
return tmp < m ? 1LL * (x - 1) * m + tmp : vecs[x][tmp - m];
}
ll query_row(int x)
{
ll tmp = atRank(x, 1, upper, roots[n + 1]);
roots[n + 1] = update(tmp, 1, upper, roots[n + 1]);
return tmp <= n ? 1LL * tmp * m : vecs[n + 1][tmp - n - 1];
}
int main()
{
scanf("%lld%lld%lld", &n, &m, &q);
upper = max(n, m) + q;
while (q--)
{
int x, y;
ll tmp;
scanf("%d%d", &x, &y);
if (y == m)
tmp = query_row(x), vecs[n + 1].push_back(tmp), printf("%lld\n", tmp);
else
{
tmp = query_col(x, y), vecs[n + 1].push_back(tmp);
printf("%lld\n", tmp);
tmp = query_row(x), vecs[x].push_back(tmp);
}
}
return 0;
}
// P3960.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 3e5 + 200, SEG = 1e7 + 200;
ll siz[SEG], n, m, q, ptot, upper;
int lson[SEG], rson[SEG], roots[SEG];
vector<ll> vecs[MAX_N];
ll atRank(ll k, int l, int r, int p)
{
if (l == r)
return l;
ll mid = (l + r) >> 1, lsiz = mid - l + 1 - siz[lson[p]];
if (k <= lsiz)
return atRank(k, l, mid, lson[p]);
else
return atRank(k - lsiz, mid + 1, r, rson[p]);
}
int update(int qx, int l, int r, int p)
{
if (p == 0)
p = ++ptot;
++siz[p];
if (l == r)
return p;
int mid = (l + r) >> 1;
if (qx <= mid)
lson[p] = update(qx, l, mid, lson[p]);
else
rson[p] = update(qx, mid + 1, r, rson[p]);
return p;
}
ll query_col(int x, int y)
{
ll tmp = atRank(y, 1, upper, roots[x]);
roots[x] = update(tmp, 1, upper, roots[x]);
return tmp < m ? 1LL * (x - 1) * m + tmp : vecs[x][tmp - m];
}
ll query_row(int x)
{
ll tmp = atRank(x, 1, upper, roots[n + 1]);
roots[n + 1] = update(tmp, 1, upper, roots[n + 1]);
return tmp <= n ? 1LL * tmp * m : vecs[n + 1][tmp - n - 1];
}
int main()
{
scanf("%lld%lld%lld", &n, &m, &q);
upper = max(n, m) + q;
while (q--)
{
int x, y;
ll tmp;
scanf("%d%d", &x, &y);
if (y == m)
tmp = query_row(x), vecs[n + 1].push_back(tmp), printf("%lld\n", tmp);
else
{
tmp = query_col(x, y), vecs[n + 1].push_back(tmp);
printf("%lld\n", tmp);
tmp = query_row(x), vecs[x].push_back(tmp);
}
}
return 0;
}
// P3960.cpp #include <bits/stdc++.h> #define ll long long using namespace std; const int MAX_N = 3e5 + 200, SEG = 1e7 + 200; ll siz[SEG], n, m, q, ptot, upper; int lson[SEG], rson[SEG], roots[SEG]; vector<ll> vecs[MAX_N]; ll atRank(ll k, int l, int r, int p) { if (l == r) return l; ll mid = (l + r) >> 1, lsiz = mid - l + 1 - siz[lson[p]]; if (k <= lsiz) return atRank(k, l, mid, lson[p]); else return atRank(k - lsiz, mid + 1, r, rson[p]); } int update(int qx, int l, int r, int p) { if (p == 0) p = ++ptot; ++siz[p]; if (l == r) return p; int mid = (l + r) >> 1; if (qx <= mid) lson[p] = update(qx, l, mid, lson[p]); else rson[p] = update(qx, mid + 1, r, rson[p]); return p; } ll query_col(int x, int y) { ll tmp = atRank(y, 1, upper, roots[x]); roots[x] = update(tmp, 1, upper, roots[x]); return tmp < m ? 1LL * (x - 1) * m + tmp : vecs[x][tmp - m]; } ll query_row(int x) { ll tmp = atRank(x, 1, upper, roots[n + 1]); roots[n + 1] = update(tmp, 1, upper, roots[n + 1]); return tmp <= n ? 1LL * tmp * m : vecs[n + 1][tmp - n - 1]; } int main() { scanf("%lld%lld%lld", &n, &m, &q); upper = max(n, m) + q; while (q--) { int x, y; ll tmp; scanf("%d%d", &x, &y); if (y == m) tmp = query_row(x), vecs[n + 1].push_back(tmp), printf("%lld\n", tmp); else { tmp = query_col(x, y), vecs[n + 1].push_back(tmp); printf("%lld\n", tmp); tmp = query_row(x), vecs[x].push_back(tmp); } } return 0; }