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安徽省赛题解的主要内容,如果未能解决你的问题,请参考以下文章
2018-2019赛季多校联合新生训练赛第三场(2018/12/8)补题题解
2018-2019赛季多校联合新生训练赛第八场(2018/12/22)补题题解