「题解」The 19th Zhejiang Provincial Collegiate Programming Contest
Before
清明和一个队友 vp 的,完全的跟榜做题,感觉发挥的还行。
B - JB Loves Comma
签到
#include <bits/stdc++.h>
std::string s;
int main() {
std::cin >> s;
int n = s.length();
for (int i = 0; i < n; ++i) {
putchar(s[i]);
if (i >= 2 && s[i] == 'b' && s[i - 1] == 'j' && s[i - 2] == 'c') putchar(',');
}
return 0;
}
C - JB Wants to Earn Big Money
签到
#include <bits/stdc++.h>
int n, m, x;
int main() {
scanf("%d %d %d", &n, &m, &x);
int ans = 0;
for (int i = 1, a; i <= n; ++i) {
scanf("%d", &a);
if (a >= x) ++ans;
}
for (int i = 1, a; i <= m; ++i) {
scanf("%d", &a);
if (a <= x) ++ans;
}
printf("%d\n", ans);
return 0;
}
A - JB Loves Math
分类讨论
- \(a = b\),答案为 \(0\)
- \(a < b\)
- \(b - a\) 为奇数,答案为 \(1\)
- \(b - a\) 为偶数,加两次奇数减一次偶数可以完成,还要考虑加偶数次奇数的情况,两者取最小值
- \(a > b\)
- \(a - b\) 为奇数,答案为 \(2\)
- \(a - b\) 为偶数,答案为 \(1\)
#include <bits/stdc++.h>
int T;
int min(int x, int y) { return x < y ? x : y; }
int main() {
scanf("%d", &T);
while (T--) {
int a, b;
scanf("%d %d", &a, &b);
if (a == b) puts("0");
else if (a < b) {
if ((b - a) & 1) puts("1");
else {
int cnt = 1, x = (b - a);
while (!(x & 1)) cnt *= 2, x >>= 1;
printf("%d\n", min(cnt, 3));
}
} else {
if ((a - b) & 1) puts("2");
else puts("1");
}
}
return 0;
}
赛时想当然了,罚时了两发。
L - Candy Machine
将糖果按甜度由小到大排序,选择的子集一定是从第一个糖果到某个糖果(为了使平均值尽量小)。
用双指针方法维护有多少糖果甜度大于平均值。
#include <bits/stdc++.h>
#define N 1000001
typedef long long ll;
int n, ans, a[N];
int max(int x, int y) { return x > y ? x : y; }
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
std::sort(a + 1, a + n + 1);
int l = 1, r = 0;
ll sum = 0;
while (r < n) {
++r;
sum += a[r];
double avg = 1.0 * sum / r;
while (l <= r && a[l] - avg <= 0) ++l;
ans = max(ans, r - l + 1);
}
printf("%d\n", ans);
return 0;
}
G - Easy Glide
可以发现有用的点只有几个滑翔点和起点终点,几个点之间互相建边,边长为所需时间(可以通过简单数学计算的出)。然后跑最短路。
#include <bits/stdc++.h>
#define N 1518
#define inf 2147483647
#define fir first
#define sec second
typedef std::pair<double, int> pdi;
bool vis[N];
double dis[N];
int ecnt, head[N];
int n, v1, v2, x[N], y[N];
struct Edge {
double w;
int nxt, v;
}e[N * N];
void add(int u, int v, double w) {
e[++ecnt].v = v, e[ecnt].w = w;
e[ecnt].nxt = head[u], head[u] = ecnt;
}
double getd(int x_, int y_ ) {
// return abs(x[x_] - x[y_]) + abs(y[x_] - y[y_]);
return (double)sqrt(1ll * (x[x_] - x[y_]) * (x[x_] - x[y_]) + 1ll * (y[x_] - y[y_]) * (y[x_] - y[y_]));
}
void Dij() {
for (int i = 1; i <= n + 2; ++i) dis[i] = inf;
dis[n + 1] = 0;
std::priority_queue<pdi, std::vector<pdi>, std::greater<> > q;
q.push({dis[n + 1], n + 1});
while (!q.empty()) {
pdi u = q.top();
q.pop();
if (vis[u.sec]) continue;
vis[u.sec] = true;
for (int i = head[u.sec]; i; i = e[i].nxt) {
int v = e[i].v;
if (!vis[v] && dis[v] > dis[u.sec] + e[i].w) {
dis[v] = dis[u.sec] + e[i].w;
q.push({dis[v], v});
}
}
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d %d", &x[i], &y[i]);
}
scanf("%d %d %d %d", &x[n + 1], &y[n + 1], &x[n + 2], &y[n + 2]);
scanf("%d %d", &v1, &v2);
add(n + 1, n + 2, 1.0 * getd(n + 1, n + 2) / v1);
for (int i = 1; i <= n; ++i) {
add(n + 1, i, 1.0 * getd(i, n + 1) / v1);
double d = getd(i, n + 2);
add(i, n + 2, (d <= v2 * 3) ? (1.0 * d / v2) : (3.0 + 1.0 * (d - v2 * 3.0) / v1));
for (int j = 1; j <= n; ++j) {
if (i == j) continue;
else {
d = getd(i, j);
add(i, j, (d <= v2 * 3) ? (1.0 * d / v2) : (3.0 + 1.0 * (d - v2 * 3.0) / v1));
}
}
}
Dij();
printf("%.12lf", dis[n + 2]);
return 0;
}
算距离炸了 int,队友不相信我的的最短路,罚时了两发。
M - BpbBppbpBB
数满足形状的空白,然后判断空白间的距离来计算数量。队友写的。
#include<bits/stdc++.h>
using namespace std;
#define ri int
#define MAXN 1010
#define pii pair< int,int >
#define fi first
#define se second
const int dx[]={0,0,0,1,1,1,1,2,2,2,2,3,3};
const int dy[]={0,0,1,-1,0,1,2,-1,0,1,2,0,1};
char s[MAXN];
int a[MAXN][MAXN],n,m;
inline bool jud(int x,int y)
{
if(x-1<1 || x+4>n || y-2<1 || y+3>m) return 0;
for(ri i=1;i<=12;i++) if(a[x+dx[i]][y+dy[i]]) return 0;
int ret=0;
for(ri i=x-1;i<=x+4;i++)
for(ri j=y-2;j<=y+3;j++)
ret+=(a[i][j]==0);
return (ret==12);
}
int main()
{
cin>>n>>m;
for(ri i=1;i<=n;i++)
{
scanf("%s",s+1);
for(ri j=1;j<=m;j++)
{
if(s[j]=='#') a[i][j]=1;
else a[i][j]=0;
}
}
vector< pii > v;
for(ri i=1;i<=n;i++)
for(ri j=1;j<=m;j++)
if(!a[i][j])
if(jud(i,j))
{
v.push_back(make_pair(i,j));
}
int ans1=0;
for(auto i=v.begin();i!=v.end();++i)
{
int x1=(*i).fi,y1=(*i).se,x2,y2;
for(auto j=i+1;j!=v.end();++j)
{
x2=(*j).fi,y2=(*j).se;
if((x1==x2 && abs(y1-y2)==7) || (y1==y2 && abs(x1-x2)==7)) ++ans1;
}
}
printf("%d %d",ans1,v.size()-ans1*2);
}
I - Barbecue
- 初始为回文串,先手必败
- 长度为 \(2\) 的串,先手必败。
- 更长的非回文串,判断两边分别删掉一个字符是否为回文,都为回文,先手必败,否则看长度减一的情况。
发现必胜必败很好算。
#include <bits/stdc++.h>
#define N 1000001
int min(int x, int y) { return x < y ? x : y; }
int max(int x, int y) { return x > y ? x : y; }
std::string s;
int n, q, cnt, p[N << 1], ans[N];
char data[N << 1], *res[2] = {"Putata", "Budada"};
void qr() {
data[0] = '~', data[cnt = 1] = '|';
for (int i = 0, st = s.length(); i < st; ++i) {
data[++cnt] = s[i], data[++cnt] = '|';
}
}
bool is(int l, int r) {
return p[2 * l + (r - l + 1) + 1] >= (r - l + 1);
}
int main() {
scanf("%d %d", &n, &q);
std::cin >> s;
qr();
for (int t = 1, r = 0, mid = 0; t <= cnt; ++t) {
if (t <= r) p[t] = min(p[(mid << 1) - t], r - t + 1);
while (data[t - p[t]] == data[t + p[t]]) ++p[t];
if (p[t] + t > r) r = p[t] + t - 1, mid = t;
}
ans[1] = ans[2] = 1;
for (int i = 3; i <= n; ++i) ans[i] = ans[i - 1] ^ 1;
for (int i = 1, l, r; i <= q; ++i) {
scanf("%d %d", &l, &r);
if (r - l + 1 <= 2) puts("Budada");
else {
if (is(l - 1, r - 1) || (is(l - 1, r - 2) && is(l, r - 1))) puts("Budada");
else puts(res[ans[r - l + 1]]);
}
}
return 0;
}
被队友忽悠写了不熟悉的 \(manacher\),调了好久。
After
昨天和三个队友 \(vp\) 了一场。
卡题了,还是简单题,气氛压抑。
唉。多练!希望正式参赛别卡。