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;
}

最后..

再过几天就是最后一次了吧.. 最后一个赛季怎么样都要加油啊..

不要犯低级错误..

不要自己卡自己

写好对拍

好好检查

用点心

posted @ 2017-11-06 19:59  Ra1nbow  阅读(197)  评论(0编辑  收藏  举报