The 18th Zhejiang Provincial Collegiate Programming Contest 补题记录(ACFGJLM)
补题链接:Here
A. League of Legends
签到题,求和判断即可
ll suma, sumb;
void solve() {
ll x;
for (int i = 1; i <= 5; ++i)cin >> x, suma += x;
for (int i = 1; i <= 5; ++i)cin >> x, sumb += x;
if (suma < sumb) cout << "Red\n"; // 注意这里要写suma<sumb
else cout << "Blue\n";
}
C. Cube
给定 8 个点(三维XYZ),判断是否是正方体
判断是否有 12 个相等的棱, 12 个相等的面对角线,4 个相等的体对角线,以及棱,面对角线和体对角线可以形成直角三角形(满足勾股定理)就行了。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll inf = 0x3f3f3f3f3f3f3f3f;
struct Point {
int x, y, z;
Point() {}
Point(int x, int y, int z): x(x), y(y), z(z) {}
bool operator<(const Point b) const {
if (x != b.x) return x < b.x;
if (y != b.y) return y < b.y;
if (z != b.z) return z < b.z;
return 0;
}
};
vector<Point>a;
set<Point>a4, ano4;
ll maxDis;
ll getDis(Point a, Point b) {
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z);
}
void init() {
maxDis = -1;
a4.clear(), ano4.clear();
}
bool sol() {
init();
for (int i = 0; i < 8; ++i)
for (int j = 0; j < i; ++j)
if (!(a[i] < a[j]) and !(a[j] < a[i]))return false;
vector<ll>diss;
for (int i = 0; i < 8; ++i)
for (int j = 0; j < i; ++j)
diss.push_back(getDis(a[i], a[j]));
sort(diss.begin(), diss.end());
for (int i = 0; i < 12; ++i)
for (int j = 0; j < j; ++j)
if (diss[i] != diss[j])return false;
for (int i = 0; i < 12; ++i)
for (int j = 0; j < j; ++j)
if (diss[12 + i] != diss[12 + j])return false;
for (int i = 0; i < 4; ++i)
for (int j = 0; j < i; ++j)
if (diss[24 + i] != diss[24 + j])return false;
if (diss[0] + diss[12] != diss[24]) return 0;
return true;
}
void solve() {
a.resize(8);
for (int i = 0; i < 8; ++i) {
cin >> a[i].x >> a[i].y >> a[i].z;
}
cout << (sol() ? "YES\n" : "NO\n");
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int _;
for (cin >> _; _--;) solve();
return 0;
}
F. Fair Distribution
\(n\) 只能减少(并且 \(n\) 不能为 \(0\)),\(m\) 只能增加,求出最终达到状态使 \(n*k=m\) 时,\(n\) 减少的值与 \(m\) 增加的值之和最小。
数论题(分治处理),类似某场ARC的题
-
\(n >= m\) 时,不难发现输出 \(n-m\) 即可
-
\(n < m\) 时,我们可以枚举n来求出最终答案,但是枚举并不是一个一个加,因为中间的值在跳跃,所以我们每次确定一个 \(l\) ,\(r = min(n,(m - 1)/((m-1)/l))\) ,而下个 \(l = r + 1\)
此时 \(k = ⌊\frac{m-1}i*i⌋\)
using ll = long long;
void solve() {
ll n, m; cin >> n >> m;
if (n > m)cout << n - m << "\n";
else {
ll cnt = 0x3f3f3f3f;
for (ll l = 1, r; l <= n; l = r + 1) {
r = min(n, (m - 1) / ((m - 1) / l));
cnt = min(cnt, (m - 1) / l * l);
}
cout << cnt + n - m << '\n';
}
}
G. Wall Game
题意待补
// 待补#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
ll lcm(ll a, ll b) {
return a / gcd(a, b) * b;
}
inline int read() {
int s = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * f;
}
const int N = 5e5 + 7;
int fa[N];
int w[N];
map<pii, int> mp;
int dir[6][2] = {0, 1, 1, 0, 1, -1, 0, -1, -1, 0, -1, 1};
int find(int x) {
return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);
}
void solve() {
int n = read();
int tot = 0;
while (n--) {
int op = read(), x = read(), y = read();
if (op == 1) {
mp[m_p(x, y)] = ++tot;
fa[tot] = tot;
w[tot] = 6;
int sum = 0;
int minus = 0;
int cnt = 0;
set<int> ss;
vector<pii> vv;
rp(k, 0, 5) {
int nx = x + dir[k][0];
int ny = y + dir[k][1];
if (mp.find(m_p(nx, ny)) == mp.end()) continue;
int id = find(mp[m_p(nx, ny)]);
vv.push_back(m_p(k, id));
if (ss.find(id) != ss.end()) cnt++;
else {
cnt++;
sum += w[id];
ss.insert(id);
}
}
int len = vv.size();
rp(k, 0, len - 1) {
rp(j, 0, len - 1) {
if (vv[k].first == 0 && vv[j].first == 1 && vv[k].second != vv[j].second) minus++;
if (vv[k].first == 1 && vv[j].first == 2 && vv[k].second != vv[j].second) minus++;
if (vv[k].first == 2 && vv[j].first == 3 && vv[k].second != vv[j].second) minus++;
if (vv[k].first == 3 && vv[j].first == 4 && vv[k].second != vv[j].second) minus++;
if (vv[k].first == 4 && vv[j].first == 5 && vv[k].second != vv[j].second) minus++;
if (vv[k].first == 5 && vv[j].first == 0 && vv[k].second != vv[j].second) minus++;
}
}
for (auto val : ss) {
// cout<<val<<" ";
fa[val] = tot;
}
// cout<<endl;
w[tot] = sum + w[tot] - 2 * cnt - 2 * minus;
// cout<<w[tot]<<endl;
// outval3(sum,cnt,minus);
} else {
cout << w[find(mp[m_p(x, y)])] << endl;
}
}
// for(auto val:mp){
// pii t=val.first;
// outval3(t.first,t.second,find(mp[t]));
// }
}
int main() {
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
J. Grammy and Jewelry
题意待补
算是比较套路的题。
根据贪心的原则,我们每次取一个宝珠后应该立马返回到原点。
而我们到这个宝珠的位置走的路和返回时走的路应该是最短路。
转换一下就是我们要取一个价值为 \(a[i]\) 的宝珠,需要消耗容量为\(2∗dis[i]\) 的时间(\(dis[i]\) 表示从 \(1\) 到 \(i\) 的最短路)。
这样就转换成了经典的完全背包问题。
关于背包问题不懂的可以看经典的背包九讲。
const int N = 3010, inf = 0x3f3f3f3f;
vector<int>e[N];
struct node {
int u, w;
node() {}
node(int u, int w): u(u), w(w) {}
friend bool operator <(node a, node b) {
return a.w > b.w;
}
};
int a[N], dis[N], vis[N], dp[N];
int n, m, t;
void Dijlstra() {
priority_queue<node> q;
for (int i = 1; i <= n; ++i)dis[i] = inf;
q.push(node{1, 0});
dis[1] = 0;
memset(vis, 0, sizeof vis);
while (!q.empty()) {
node t = q.top();
q.pop();
vis[t.u] = 1;
int u = t.u;
int w = t.w;
// cout << u << " " << w << endl;
for (auto v : e[u]) {
// cout << v << " " << dis[v] << endl;
if (!vis[v] && dis[v] > w + 1) {
dis[v] = w + 1;
q.push(node{v, dis[v]});
}
}
}
}
void solve() {
cin >> n >> m >> t;
for (int i = 2; i <= n; ++i)cin >> a[i];
for (int i = 1; i <= m; ++i) {
int u, v; cin >> u >> v;
if (u == v)continue;
e[u].push_back(v);
e[v].push_back(u);
}
Dijlstra();
for (int i = 1; i <= n; ++i)
for (int j = dis[i] * 2; j <= t; ++j)
dp[j] = max(dp[j], dp[j - dis[i] * 2] + a[i]);
for (int i = 1; i <= t; ++i)cout << dp[i] << (i == t ? "\n" : " ");
}
L. String Freshman
读了半天题,结果题意有问题。。。
给的字符串应该是匹配串。
因此我们判断一下是否存在前缀子串的最长公共前后缀长度不为 \(0\)(即 next
数组不为 \(0\) )。
更简单的做法就是判断是否有字符和第一个字符相等即可。
void solve() {
int n; string s;
cin >> n >> s;
for (int i = 1; i <= n - 1; ++i)
if (s[i] == s[0]) {
cout << "Wrong Answer\n";
return ;
}
cout << "Correct\n";
}
M. Game Theory
输出 0.0000
即可。
首先我们知道每个学生是不知道 \(Grammy\) 的选择,而又因为学生每次都是最优的选择,因此我们可以先算出一个学生在 \([1 ,20]\) 选择一个数后赢的分数的期望,每次都选择这\(20\) 个数中期望最大的即可。
我们写出计算期望的代码可以发现,每个数赢的分数的期望都是 \(0\) 。
而学生和 \(Grammy\) 的分数是互补的,只有一个输了,另一个赢了的情况
所以 \(Grammy\) 胜利的期望也是 \(0\)
void solve() {
int n; cin >> n;
cout << fixed << setprecision(4) << 0.0;
}