2017 ACM/ICPC 广西邀请赛 题解

题目链接  Problems

HDOJ上的题目顺序可能和现场比赛的题目顺序不一样,

我这里的是按照HDOJ的题目顺序来写的。

Problem 1001

签到

#include <bits/stdc++.h>

using namespace std;

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

typedef long long LL;

LL n, f[31];
int ans;


int main(){

	f[1] = 1LL;
	for (LL i = 2; i <= 15; ++i){
		f[i] = 1LL;
		rep(j, 1, i) f[i] *= i;
	}

	while (~scanf("%lld", &n)){
		ans = 0;
		rep(i, 1, 15) if (f[i] <= n) ans = max(ans, i);
		printf("%d\n", ans);
	}	


	return 0;
}

 

 

Problem 1002

这道题的话,其实一个点上是可以有多种颜色的

因为最多只有51种颜色,所以我们维护51棵线段树即可。

我们对y坐标建立线段树,对于每个y,我们只需要知道最小的x在哪里即可。

因为他的询问的x坐标下界总是1,那么我们只要看看y1到y2的最小值是否小于等于给定的x即可。

询问的时候做51次子询问就可以了。

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

typedef long long LL;

const int N = 2e6 + 10;

int X, c, d, x, y, op, ans, ret, cnt;
int root[53];
int l[N], r[N], v[N];

void update(int &i, int L, int R, int x, int val){
	if (i == 0){
		i = ++cnt;
		v[i] = val;
	}

	v[i] = min(v[i], val);
	if (L == R) return;

	int mid = (L + R) >> 1;
	if (x <= mid) update(l[i], L, mid, x, val);
	else update(r[i], mid + 1, R, x, val);
}

void query(int i, int L, int R){
	if (ret || i == 0) return;
	if (c <= L && R <= d){
		if (v[i] <= X) ret = 1;
		return;
	}

	int mid = (L + R) >> 1;
	if (c <= mid) query(l[i], L, mid);
	if (d >  mid) query(r[i], mid + 1, R);
}	

int main(){

	while (true){
		scanf("%d", &op);
		if (op == 3) break;
		if (op == 0){
			rep(i, 1, cnt) l[i] = r[i] = 0;
			memset(root, 0, sizeof root);
			cnt = 0;
		}

		if (op == 1){
			scanf("%d%d%d", &x, &y, &c);
			update(root[c], 1, 1000000, y, x);
		}

		if (op == 2){
			scanf("%d%d%d", &X, &c, &d);
			ans = 0;
			rep(i, 0, 50){
				ret = 0;
				query(root[i], 1, 1000000);
				ans += ret;
			}
			printf("%d\n", ans);
		}
	}


	return 0;
}

 

 

 

 

Problem 1003

我们对于每一条边,找到所有包含这条边的三元环,个数计为x

然后这对答案的贡献就是$C_{x}^{2}$

判断两点之间是否有边的时候要手写哈希才能过

#include <bits/stdc++.h>

const int N = 2e5 + 10;

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

namespace Hashmap{
	const int P = 1000007, seed = 2333;
	int u[N << 2], v[N << 2], nt[N << 2];
	int head[P], inum;
	inline void init(){
		inum = 0;
		memset(u, 0, sizeof u);
		memset(v, 0, sizeof v);
		memset(nt, 0, sizeof nt);
		memset(head, 0, sizeof head);
	}

	inline void add(int _u, int _v){
		int t = (_u * seed + _v) % P;
		u[++inum] = _u, v[inum] = _v, nt[inum] = head[t], head[t] = inum;
	}

	inline bool query(int _u, int _v){
		int t = (_u * seed + _v) % P;
		for (int p = head[t]; p; p = nt[p])
			if (u[p] == _u && v[p] == _v) return 1;
		return 0;
	}
}

using namespace std;
using namespace Hashmap;

typedef long long LL;

vector<int> a[N];

struct ss{ int x, y; } e[N];

int n, m;

int main(){

	while (~scanf("%d%d",&n, &m)){
		init();
		rep(i, 1, n) a[i].clear();
		rep(i, 1, m){
			int x, y;
			scanf("%d%d", &x, &y);
			e[i].x = x;
			e[i].y = y;
			a[x].push_back(y);
			a[y].push_back(x);
			add(x, y);
			add(y, x);
		}

		LL ans = 0;
		rep(i, 1, m){
			int x = e[i].x, y = e[i].y;
			if (a[e[i].y].size() < a[e[i].x].size()) swap(x, y);
			LL tot = 0;
			for (auto u: a[x]) if (query(u, y))  tot++;
			ans += tot * (tot - 1) / 2;
		}

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

 

 

Problem 1004

这题规律找了半天……

$f[n] = f[n - 1] + 5f[n - 2] + f[n - 3] - f[n - 4]$

然后矩阵加速下就可以了

#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 LL mod = 1e9 + 7;

struct Matrix{
	LL arr[6][6];
} f, unit, a;


LL m, k;
int n;

Matrix Add(Matrix a, Matrix b){
	Matrix c;
	rep(i, 1, n) rep(j, 1, n){
		c.arr[i][j] = (a.arr[i][j] + b.arr[i][j]) % mod;
	}
	return c;
}

Matrix Mul(Matrix a, Matrix b){
	Matrix c;
	rep(i, 1, n) rep(j, 1, n){
		c.arr[i][j] = 0;
		rep(k, 1, n) (c.arr[i][j] += (a.arr[i][k] * b.arr[k][j] % mod)) %= mod;
	}
	return c;
}

Matrix Pow(Matrix a, LL k){
	Matrix ret(unit); for (; k; k >>= 1, a = Mul(a, a)) if (k & 1) ret = Mul(ret, a); return ret;
}


int main(){

	n = 4;

	memset(f.arr, 0, sizeof f.arr);
	memset(a.arr, 0, sizeof a.arr);
	memset(unit.arr, 0, sizeof unit.arr);

	rep(i, 1, n) unit.arr[i][i] = 1;
	f.arr[1][1] = 1;
	f.arr[1][2] = 5;
	f.arr[1][3] = 1;
	f.arr[1][4] = 1000000006;
	f.arr[2][1] = 1;
	f.arr[3][2] = 1;
	f.arr[4][3] = 1;
	
	a.arr[1][1] = 36;
	a.arr[2][1] = 11;
	a.arr[3][1] = 5;
	a.arr[4][1] = 1;

	while (~scanf("%lld", &m)){
		if (m == 1LL){ puts("1");  continue;}
		if (m == 2LL){ puts("5");  continue;}
		if (m == 3LL){ puts("11"); continue;}
		if (m == 4LL){ puts("36"); continue;}
		if (m == 5LL){ puts("95"); continue;}

		k = m - 4;

		Matrix b = Pow(f, k);
		Matrix c = Mul(b, a);
		printf("%lld\n", c.arr[1][1]);		
	}

	return 0;
}

 

 

Problem 1010

这道题的话先转DFS序,然后求出以每个点为根的子树的对应区间,

于是就转化成了求区间里选一个数和x异或后的最大值。

可持久化trie即可。

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


typedef long long LL;

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

int n, m, tot = 0;
int rt[N], id[M], t[M][2];
int l, r, x;
int a[N], c[N], L[N], R[N], g[N];
int ti;
int u;


vector <int> v[N];


inline void insert(int pre, int x, int k){

	int now = rt[k] = ++tot; id[tot] = k;

	dec(i, 30, 0){
		int j = (x >> i) & 1;
		t[now][j ^ 1] = t[pre][j ^ 1];
		t[now][j] = ++tot;
		id[tot] = k;
		now = t[now][j];
		pre = t[pre][j];
	}
}


inline int query(int l, int r, int x){

	int ans = 0, tmp = rt[r];

	dec(i, 30, 0){
		if (id[tmp] < l) break;
		int j = ((x >> i) & 1) ^ 1;
		if (id[t[tmp][j]] >= l) ans |= (1 << i);
		else j ^= 1;
		tmp = t[tmp][j];
	}

	return ans;
}

void dfs(int x){
	L[x]  = ++ti;
	g[ti] = a[x];
	for (auto u : v[x]){
		dfs(u);
	}
	R[x] = ti;
}


int main(){

	while (~scanf("%d%d", &n, &m)){
		memset(id, 0, sizeof id);
		memset(rt, 0, sizeof rt);
		memset(t, 0, sizeof t);
		memset(L, 0, sizeof L);
		memset(R, 0, sizeof R);

		tot = 0;
		ti = 0;

		rep(i, 0, n + 1) v[i].clear();
		rep(i, 1, n) scanf("%d", a + i);
		rep(i, 2, n){
			scanf("%d", &x);
			v[x].push_back(i);
		}

		dfs(1);

		id[0] = -1;
		insert(0, 0, 0);
		
		rep(i, 1, n) insert(rt[i - 1], g[i], i);

		rep(i, 1, m){
			scanf("%d%d", &u, &x);
			printf("%d\n", query(L[u], R[u], x));
		}

	}
	return 0;
}

 

posted @ 2017-09-01 21:26  cxhscst2  阅读(333)  评论(0编辑  收藏  举报