Codeforces Educational Round 33 题解

题目链接   Codeforces Educational Round 33

Problem A

按照题目模拟,中间发现不对就直接输出NO。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define MP		make_pair
#define fi		first
#define se		second


typedef long long LL;

int a, b, c, n;


int main(){
	
	a = 1, b = 2, c = 3;
	scanf("%d", &n);
	rep(i, 1, n){
		int x;
		scanf("%d", &x);
		if (x != a && x != b) return 0 * puts("NO");
		if (x == a) swap(b, c); else swap(a, c);
	}

	puts("YES");	
	return 0;
}

Problem B

打表然后塞到set里面,然后查找一下。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define MP		make_pair
#define fi		first
#define se		second


typedef long long LL;

int c[20];
int a[100010];
int n;
int cnt, et;
set <int> s;


int main(){

	rep(i, 1, 10){
		int a = (1 << i) - 1;
		int b = (1 << (i - 1));
		s.insert(a * b);
	}

	rep(i, 1, et) printf("%d\n", c[i]);

	scanf("%d", &n);
	rep(i, 1, n) if (n % i == 0) a[++cnt] = i;
	dec(i, cnt, 1) if (s.count(a[i])) return 0 * printf("%d\n", a[i]);;
	return 0;
}

Problem C

在每个连通块里面找个权值最小的然后加起来即可。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define MP		make_pair
#define fi		first
#define se		second


typedef long long LL;

const int N = 1e6 + 10;


LL  a[N];
LL  now;
LL  ans = 0;
int vis[N];
vector <int> v[N];
int n, m;

void dfs(int x){
	vis[x] = 1;
	now = min(now, a[x]);
	for (auto u : v[x]){
		if (!vis[u]) dfs(u);
	}
}
	

int main(){

	scanf("%d%d", &n, &m);
	rep(i, 1, n) scanf("%lld", a + i);

	rep(i, 1, m){
		int x, y;
		scanf("%d%d", &x, &y);
		v[x].push_back(y);
		v[y].push_back(x);
	}

	rep(i, 1, n) if (!vis[i]){
		now = 1e10;
		dfs(i);
		ans += now;
	}

	printf("%lld\n", ans);
	return 0;
}

Problem D

考虑每一天的时候,记录min和max,分别表示钱的下限值和上限值。

如果min都超过d了那肯定不行了,输出-1。

check的时候根据mx是否非负来决定是否更新答案。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

int n, d;
int x;
int mi = 0, mx = 0;
int ans;


int main(){

	scanf("%d%d", &n, &d);
	rep(i, 1, n){
		scanf("%d", &x);
		if (x){
			mi += x, mx += x;
			if (mi > d) return 0 * puts("-1");
			mx = min(mx, d);
		}

		else{
			if (mx >= 0) mi = max(mi, 0);
			else ++ans, mx = d, mi = 0;
		}
	}

	printf("%d\n", ans);
	return 0;
}

Problem E

首先来个预处理,把所有的数的质因子以及指数求出来。

然后对于每一个质因子c,找到他的指数d。

转化成盒子里面放小球的问题。

(盒子不同,小球相同,允许空盒子的情况)

那么当前质因子c对答案的贡献即为$C(y + d - 1, d)$

由于各质因子之间是独立的,所以直接相乘即可。

最后还有-1的情况,对整个ans乘上$2^{y - 1}$即可。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define MP		make_pair
#define fi		first
#define se		second


typedef long long LL;
typedef pair <int, int> PII;

const int N   = 2e6 + 10;
const int mod = 1e9 + 7;

int fac[N];
int c[N];
int val[N];
int ret, q, x, y;
int inv[N];
vector <PII> pri[N];



inline int Pow(int a, int b, int mod){
        int ret = 1;
        for (; b; b >>= 1, a = 1ll * a * a % mod) if (b & 1) ret = 1ll * ret * a % mod;
        return ret;
}

inline int C(int n, int k){ return 1ll * fac[n] * inv[k] % mod * inv[n - k] % mod; }


void init(){
	fac[0] = 1;
	rep(i, 1, 2e6 + 3) fac[i] = 1ll * fac[i - 1] * i % mod;
	rep(i, 0, 2e6 + 3) inv[i] = Pow(fac[i], mod - 2, mod);
	rep(i, 1, 1e6 + 3) val[i] = i;
	rep(i, 2, 1e6 + 3) if (!c[i]){
		for (int j = i * 2; j <= 1e6 + 3; j += i){
			c[j] = 1;
	 		int cnt = 0;
			while (val[j] % i == 0) val[j] /= i, ++cnt;
			pri[j].push_back(MP(i, cnt));
		}
	}

	rep(i, 2, 1e6 + 3) if (val[i] > 1)
		pri[i].push_back(MP(i, 1));
}



int main(){

	init();
	scanf("%d", &q);
	while (q--){
		int x, y;
		scanf("%d%d", &x, &y);
		ret = Pow(2, y - 1, mod);
		for (auto u : pri[x]){
			int d = u.se;
			ret = 1ll * ret * C(y + d - 1, d) % mod;
		}
		printf("%d\n", ret);
	}

	return 0;
}

Problem F

对于每一个结点,维护以他为根的子树中深度在[l, r]范围内的所有点的权值的最小值。

一开始每个点在空树的基础上在自己这个深度插入自己的权值。

每个点的插入复杂度为$O(logn)$,因为要开$logn$棵线段树。

然后dfs一遍,做$n$次线段树合并即可。

查询的时候对询问的距离$d$加上当前结点的深度$deep$,这样就构成了一个询问区间$[1, d + deep]$。

为什么左端点是$1$呢,因为当前结点代表的线段树在$[1, deep - 1]$内都没有信息,那么$[1, d + deep]$就可以等效题目的询问区间。

 

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define MP		make_pair
#define fi		first
#define se		second

typedef long long LL;

const int N = 1e5 + 10;
const int M = 2e7 + 10;

int father[N], deep[N];
int n, r;
vector <int> v[N];
int a[N];
int t[M], ls[M], rs[M];
int tot = 0;
int val[M];
int m;
int ans;


void dfs(int x, int fa, int dep){
	deep[x] = dep;
	father[x] = fa;
	for (auto u : v[x]){
		if (u == fa) continue;
		dfs(u, x, dep + 1);
	}
}

int ins(int x, int a, int b, int c, int p){
	int y = ++tot;
	val[y] = min(val[x], p);
	if (a == b) return y;
	int mid = (a + b) >> 1;
	if (c <= mid) ls[y] = ins(ls[x], a, mid, c, p), rs[y] = rs[x];
	else ls[y] = ls[x], rs[y] = ins(rs[x], mid + 1, b, c, p);
	return y;
}

int ask(int x, int a, int b, int d){
	if (b <= d) return val[x];
	int mid = (a + b) >> 1, t = ask(ls[x], a, mid, d);
	if (d > mid) t = min(t, ask(rs[x], mid + 1, b, d));
	return t;
}

int merge1(int x, int y, int a, int b){
	if (!x || !y) return x + y;
	int z = ++tot;
	val[z] = min(val[x], val[y]);
	if (a == b) return z;
	int mid = (a + b) >> 1;
	ls[z] = merge1(ls[x], ls[y], a, mid);
	rs[z] = merge1(rs[x], rs[y], mid + 1, b);
	return z;
}

void work(int x, int fa){
	for (auto u : v[x]){ if (u == fa) continue; work(u, x); }
	for (auto u : v[x]){
		if (u == fa) continue;
		t[x] = merge1(t[x], t[u], 1, n);
	}
}

int main(){

	scanf("%d%d", &n, &r);
	rep(i, 1, n) scanf("%d", a + i);
	rep(i, 0, 2e7) val[i] = 2147000000;

	rep(i, 2, n){
		int x, y;
		scanf("%d%d", &x, &y);
		v[x].push_back(y);
		v[y].push_back(x);
	}

	dfs(r, 0, 1);
	rep(i, 1, n) t[i] = ins(0, 1, n, deep[i], a[i]);
	work(r, 0);
	ans = 0;
	scanf("%d", &m);
	while (m--){
		int x, y;
		scanf("%d%d", &x, &y);
		x = ((x + ans) % n) + 1;
		y = ((y + ans) % n);
		y += deep[x];
		if (y > n) y = n;
		printf("%d\n", ans = ask(t[x], 1, n, y));
	}

	return 0;
}

 

posted @ 2017-11-29 01:07  cxhscst2  阅读(159)  评论(0编辑  收藏  举报