noip2016
因为去年阴影太大拖到现在才做..
下面的题号都是uoj上的啊
#261. 【NOIP2016】天天爱跑步
去年对此一窍不通
但现在我想到了长链剖分、线段树合并
硬是不知道怎么$O(n)$处理询问我好菜啊
维护$w_x-dep_x$和$w_x+dep_x$,分别对应往上走的链和往下走的链
题目就是要找子树内与当前根相同的值的个数
那么在下去子树前先记录现在的值,再用做完子树后的值减去它就行了
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> using namespace std; const int Maxn = 300010; const int N = 300000; const int lg = 20; struct node { int y, next; }a[Maxn<<1]; int first[Maxn], len; void ins(int x, int y) { len++; a[len].y = y; a[len].next = first[x]; first[x] = len; } int n, m; int w[Maxn], dep[Maxn], fa[Maxn][lg]; int ans[Maxn]; void dfs(int x) { for(int i = 1; i < lg; i++) fa[x][i] = fa[fa[x][i-1]][i-1]; for(int k = first[x]; k; k = a[k].next){ int y = a[k].y; if(y == fa[x][0]) continue; fa[y][0] = x; dep[y] = dep[x]+1; dfs(y); } } int getlca(int x, int y) { if(dep[x] < dep[y]) swap(x, y); for(int i = lg-1; i >= 0; i--) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i]; if(x == y) return x; for(int i = lg-1; i >= 0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i]; return fa[x][0]; } struct qnode { int x, op, s; qnode(int x = 0, int op = 0, int s = 0) : x(x), op(op), s(s) {} }; vector <qnode> vec[Maxn]; int s[2][Maxn<<1]; void getans(int x) { int last0 = s[0][w[x]+dep[x]], last1 = s[1][w[x]-dep[x]+N]; int sz = vec[x].size(); for(int i = 0; i < sz; i++){ qnode o = vec[x][i]; s[o.op][o.x] += o.s; } for(int k = first[x]; k; k = a[k].next){ int y = a[k].y; if(y == fa[x][0]) continue; getans(y); } ans[x] += s[0][w[x]+dep[x]]-last0+s[1][w[x]-dep[x]+N]-last1; } int main() { int i, j, k; scanf("%d%d", &n, &m); for(i = 1; i < n; i++){ int x, y; scanf("%d%d", &x, &y); ins(x, y); ins(y, x); } dep[1] = 1; dfs(1); for(i = 1; i <= n; i++) scanf("%d", &w[i]); for(i = 1; i <= m; i++){ int x, y; scanf("%d%d", &x, &y); int lca = getlca(x, y); if(dep[x]-dep[lca] == w[lca]) ans[lca]--; vec[x].push_back(qnode(dep[x], 0, 1)); vec[fa[lca][0]].push_back(qnode(dep[x], 0, -1)); vec[y].push_back(qnode(dep[x]-2*dep[lca]+N, 1, 1)); vec[fa[lca][0]].push_back(qnode(dep[x]-2*dep[lca]+N, 1, -1)); } getans(1); for(i = 1; i <= n; i++) printf("%d%c", ans[i], i==n?'\n':' '); return 0; }
#262. 【NOIP2016】换教室
去年想到dp方程不敢写,真的菜
$f_{i,j,0/1}$表示前$i$个用了$j$次申请,第$i-1$次有没有申请
很好转移的
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int Maxn = 2010; const int Maxm = 310; const int inf = 0x7fffffff; int n, m, v, e; double f[2][Maxn][2]; int dis[Maxm][Maxm]; int c[Maxn], d[Maxn]; double p[Maxn]; int _min(int x, int y) { return x < y ? x : y; } double _min(double x, double y) { return x < y ? x : y; } int main() { int i, j, k; scanf("%d%d%d%d", &n, &m, &v, &e); for(i = 1; i <= n; i++) scanf("%d", &c[i]); for(i = 1; i <= n; i++) scanf("%d", &d[i]); for(i = 1; i <= n; i++) scanf("%lf", &p[i]); for(i = 1; i <= v; i++) for(j = 1; j <= v; j++) dis[i][j] = inf; for(i = 1; i <= e; i++){ int x, y, d; scanf("%d%d%d", &x, &y, &d); dis[x][y] = dis[y][x] = _min(d, dis[x][y]); } for(k = 1; k <= v; k++){ for(i = 1; i <= v; i++) if(dis[i][k] != inf && i != k){ for(j = 1; j <= v; j++) if(dis[k][j] != inf && i != j && j != k){ dis[i][j] = _min(dis[i][j], dis[i][k]+dis[k][j]); } } } for(i = 1; i <= v; i++) dis[i][i] = 0; for(i = 0; i <= m; i++) f[0][i][0] = f[0][i][1] = inf; f[0][0][0] = 0; f[0][1][1] = 0; int st = 0; for(k = 2; k <= n; k++){ st ^= 1; for(i = 0; i <= m; i++){ f[st][i][0] = _min(f[st^1][i][0]+dis[c[k-1]][c[k]], f[st^1][i][1]+p[k-1]*dis[d[k-1]][c[k]]+(1-p[k-1])*dis[c[k-1]][c[k]]); if(i) f[st][i][1] = _min(f[st^1][i-1][0]+p[k]*dis[c[k-1]][d[k]]+(1-p[k])*dis[c[k-1]][c[k]], f[st^1][i-1][1]+p[k]*p[k-1]*dis[d[k-1]][d[k]]+p[k]*(1-p[k-1])*dis[c[k-1]][d[k]]+ (1-p[k])*p[k-1]*dis[d[k-1]][c[k]]+(1-p[k])*(1-p[k-1])*dis[c[k-1]][c[k]]); else f[st][i][1] = inf; } } double ans = inf; for(i = 0; i <= m; i++) ans = _min(ans, _min(f[st][i][0], f[st][i][1])); printf("%.2lf\n", ans); return 0; }
#264. 【NOIP2016】蚯蚓
去年没想到
用三个队列维护就行了
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <queue> #define LL long long using namespace std; const LL Maxn = 100010; const LL inf = (LL)1<<60; LL a[Maxn]; LL n, m, q, u, v, t; queue <LL> que[3]; int main() { LL i, j, k; scanf("%lld%lld%lld%lld%lld%lld", &n, &m, &q, &u, &v, &t); for(i = 1; i <= n; i++) scanf("%lld", &a[i]); sort(a+1, a+n+1); for(i = n; i >= 1; i--) que[0].push(a[i]); for(i = 1; i <= m; i++){ LL x0, x1, x2; if(!que[0].empty()) x0 = que[0].front(); else x0 = -inf; if(!que[1].empty()) x1 = que[1].front(); else x1 = -inf; if(!que[2].empty()) x2 = que[2].front(); else x2 = -inf; LL nl, l1, l2; if(x0 >= x1 && x0 >= x2){ nl = x0+(i-1)*q; que[0].pop(); l1 = nl*u/v, l2 = nl-l1; que[1].push(l1-i*q); que[2].push(l2-i*q); } else if(x1 >= x0 && x1 >= x2){ nl = x1+(i-1)*q; que[1].pop(); l1 = nl*u/v, l2 = nl-l1; que[1].push(l1-i*q); que[2].push(l2-i*q); } else { nl = x2+(i-1)*q; que[2].pop(); l1 = nl*u/v, l2 = nl-l1; que[1].push(l1-i*q); que[2].push(l2-i*q); } if(i%t == 0) printf("%lld ", nl); } printf("\n"); for(i = 1; i <= n+m; i++){ LL x0, x1, x2; if(!que[0].empty()) x0 = que[0].front(); else x0 = -inf; if(!que[1].empty()) x1 = que[1].front(); else x1 = -inf; if(!que[2].empty()) x2 = que[2].front(); else x2 = -inf; LL nl, l1, l2; if(x0 >= x1 && x0 >= x2){ nl = x0+m*q; que[0].pop(); } else if(x1 >= x0 && x1 >= x2){ nl = x1+m*q; que[1].pop(); } else { nl = x2+m*q; que[2].pop(); } if(i%t == 0) printf("%lld ", nl); } return 0; }
#265. 【NOIP2016】愤怒的小鸟
去年最大的阴影,想的$O(2^nn^2)$写的$O(2^nn^3)$强行卡掉自己15分
预处理出某两个点为抛物线经过的点
然后dp就行了
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #define eps 1e-10 using namespace std; const int Maxn = 20; int f[1<<18], n, m; int g[Maxn][Maxn]; double X[Maxn], Y[Maxn]; double _abs(double x) { return x < 0 ? -x : x; } double zero(double x) { return _abs(x) < eps ? 1 : 0; } void down(int &x, int y) { if(x > y) x = y; } int main() { int i, j, k; int T; scanf("%d", &T); while(T--){ scanf("%d%d", &n, &m); for(i = 0; i < n; i++) scanf("%lf%lf", &X[i], &Y[i]); for(i = 0; i < n; i++){ for(j = i+1; j < n; j++){ g[i][j] = 0; if(zero(X[i]-X[j]) || zero(Y[i]/X[i]-Y[j]/X[j])) continue; double A = (Y[i]*X[j]-Y[j]*X[i])/(X[i]*X[j]*(X[i]-X[j])), B = (Y[i]*X[j]*X[j]-Y[j]*X[i]*X[i])/(X[i]*X[j]*(X[j]-X[i])); if(A > eps) continue; for(k = 0; k < n; k++) if(zero(A*X[k]*X[k]+B*X[k]-Y[k])) g[i][j] += 1<<k; } } memset(f, 63, sizeof(f)); f[0] = 0; int mx = 1<<n; for(i = 0; i < mx; i++){ for(j = 0; j < n; j++) down(f[i|(1<<j)], f[i]+1); for(j = 0; j < n; j++){ for(k = 0; k < n; k++) down(f[i|g[j][k]], f[i]+1); } } printf("%d\n", f[mx-1]); } return 0; }
最后..
再过几天就是最后一次了吧.. 最后一个赛季怎么样都要加油啊..
不要犯低级错误..
不要自己卡自己
写好对拍
好好检查
用点心
嗯
作者:Ra1nbow
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。