2019安徽省赛题解

Posted uid001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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. 卡牌对决

贪心, 前$\facn2$场尽量取最大, 后$\fracn2$场尽量取最小.

 

#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)$

 

以上是关于2019安徽省赛题解的主要内容,如果未能解决你的问题,请参考以下文章

2021安徽省赛

2016安徽省赛 - 木条染色 离散化+线段树

2018-2019赛季多校联合新生训练赛第三场(2018/12/8)补题题解

2018-2019赛季多校联合新生训练赛第八场(2018/12/22)补题题解

2018-2019赛季多校联合新生训练赛第六场(2018/12/15)补题题解

2021年安徽省大数据与人工智能应用竞赛人工智能(网络赛)-本科组赛题