2019安徽省赛题解

A.机器人足球

模拟

 

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;

double dis(int x1, int y1, int x2, int y2) {
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

int main() {
	int x, y;
	scanf("%d%d", &x, &y);
	double d = dis(x,y,100,10)-10;
	printf("%.3lf\n",max(d,0.));
}

 

 

 

B.纸牌识别

模拟

 

#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
typedef pair<int,int> pii;

char x;
int y;
int a[200];
set<pii> s;

int main() {
	a['P']=a['K']=a['H']=a['T']=13;
	while (~scanf(" %c%d", &x, &y)) {
		if (s.count(pii(x,y))) return puts("GRESKA"),0;
		s.insert(pii(x,y));
		--a[x];
	}
	printf("%d %d %d %d\n",a['P'],a['K'],a['H'],a['T']);
}

 

 

C. 卡牌对决

贪心, 前$\fac{n}{2}$场尽量取最大, 后$\frac{n}{2}$场尽量取最小.

 

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <set>
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
const int N = 1e5+10;
int n, a[N];
set<int> Bob, Alice;

int main() {
	scanf("%d", &n);
	REP(i,1,n) { 
		scanf("%d",a+i);
		Bob.insert(a[i]);
	}
	REP(i,1,2*n) if (!Bob.count(i)) Alice.insert(i);
	int ans = 0;
	sort(a+1,a+1+n/2,greater<int>());
	REP(i,1,n/2) {
		int x = *(--Alice.end());
		if (x>a[i]) ++ans, Alice.erase(x);
	}
	sort(a+1+n/2,a+1+n);
	REP(i,1,n/2) {
		int x = *Alice.begin();
		if (x<a[i]) ++ans, Alice.erase(x);
	}
	printf("%d\n", ans);
}

 

 

D. 自驾游

先跑2次dijkstra求出$N$到每个点最短路, 再建图跑一次dijkstra求出$1->N$最短路即为最少花费.

 

#include <iostream>
#include <cstdio>
#include <queue>
#include <string.h>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define pb push_back
using namespace std;
typedef long long ll;

const int N = 5e4+10;
int n, m;
struct _ {int to,w;};
vector<_> g1[N], g2[N], g3[N];
ll d1[N], d2[N], d3[N];
int vis[N], u[N], v[N], p[N], q[N];
struct node {
	int id;
	ll w;
	bool operator < (const node &rhs) const {
		return w>rhs.w;
	}
};
priority_queue<node> pq;

void dij(vector<_> g[], ll d[], int s) {
	memset(d,0x3f,sizeof d1);
	memset(vis,0,sizeof vis);
	pq.push({s,d[s]=0});
	while (pq.size()) {
		int u = pq.top().id; pq.pop();
		if (vis[u]) continue;
		vis[u] = 1;
		for (auto &e:g[u]) {
			ll dd = e.w+d[u];
			if (dd<d[e.to]) pq.push({e.to,d[e.to]=dd});
		}
	}
}

int main() {
	scanf("%d%d", &n, &m);
	REP(i,1,m) {
		scanf("%d%d%d%d", u+i, v+i, p+i, q+i);
		g1[v[i]].pb({u[i],p[i]});
		g2[v[i]].pb({u[i],q[i]});

	}
	dij(g1,d1,n);
	dij(g2,d2,n);
	REP(i,1,m) {
		int c = 0;
		if (d1[v[i]]+p[i]>d1[u[i]]) ++c;
		if (d2[v[i]]+q[i]>d2[u[i]]) ++c;
		g3[u[i]].pb({v[i],c});
	}
	dij(g3,d3,1);
	printf("%lld\n", d3[n]);
}

 

 

G. 括号序列

$dp$求出长为$x$, 左括号比右括号多$y$个时的方案数. 然后从前往后枚举, 若放'('的方案数不少于$k$, 则放'(', 否则放')'.

注意方案数是指数级, 会爆long long.

 

#include <iostream>
#define REP(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
typedef long long ll;

const int N = 2010;
int n, k;
ll f[N][N];
char ans[N];

int main() {
	scanf("%d%d", &n, &k);
	f[0][0] = 1;
	ll INF = 1e18+10;
	REP(i,1,n) REP(j,0,n) if (f[i-1][j]) { 
		f[i][j+1] += f[i-1][j];
		if (j) f[i][j-1] += f[i-1][j];
		f[i][j+1] = min(f[i][j+1], INF);
		f[i][j-1] = min(f[i][j-1], INF);
	}
	int now = 0;
	REP(i,1,n) {
		if (f[n-i][now+1]>=k) ans[i]='(',++now;
		else ans[i]=')',k-=f[n-i][now+1],--now;
	}
	puts(ans+1);
}

 

 

H. 不要回文

大回文一定包含小回文, 只用判断长为2和3的回文即可.

 

#include <iostream>
#include <cstdio>
#include <string.h>
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;

const int N = 1e6+10;
int n, a[N];
char s[N];

int main() {
	scanf("%s", s+1);
	n = strlen(s+1);
	REP(i,1,n) a[i]=s[i];
	int ans = 0, cur = 0;
	REP(i,1,n) {
		if (a[i]==a[i-1]) ++ans,a[i]=--cur;
		if (i>=2&&a[i]==a[i-2]) ++ans,a[i]=--cur;
	}
	printf("%d\n", ans);
}

 

 

I. 你的名字

判断一个串是否是另一个串的子序列, 二分$O(nlogn)$, 或者序列自动机$O(n\Sigma)$

 

上一篇:题解 CF1426E - Rock, Paper, Scissors


下一篇:Alice&Brown(AtCoder-2400)