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