NEERC训练实录

听说这里可以做一些idea比较好的题..

那就做做吧

2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest

A. Auxiliary Project

有$7$就要$7$

余$1$就少一个$7$多一个$4$,余$2$就多一个$1$

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
int n;
int main() {
	freopen("auxiliary.in", "r", stdin);
	freopen("auxiliary.out", "w", stdout);
	int i, j, k;
	scanf("%d", &n);
	if(n%3 == 0) printf("%d\n", n/3*7);
	else if(n%3 == 1) printf("%d\n", (n/3-1)*7+4);
	else printf("%d\n", n/3*7+1);
	return 0;
}

B. Boolean Satis ability

好像很模拟??

C. Consonant Fencity

$2^17$枚举所有情况再算答案

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int Maxn = 1000010;
char s[Maxn];
int n;
bool v[26];
int num[26], l;
int mp[26][26];
int main() {
	freopen("consonant.in", "r", stdin);
	freopen("consonant.out", "w", stdout);
	int i, j, k;
	scanf("%s", s+1);
	n = strlen(s+1);
	v['a'-'a'] = v['e'-'a'] = v['i'-'a'] = v['o'-'a'] = v['u'-'a'] = v['w'-'a'] = v['y'-'a'] = true;
	l = 0;
	for(i = 1; i < 26; i++) if(!v[i]) num[i] = l++;
	for(i = 2; i <= n; i++){
		if(!v[s[i]-'a'] && !v[s[i-1]-'a']) mp[num[s[i]-'a']][num[s[i-1]-'a']]++;
	}
	int ans = 0, res = 0;
	for(i = 1; i < 1<<l; i++){
		int ret = 0;
		for(j = 0; j < l; j++){
			for(k = 0; k < l; k++){
				if((i&(1<<j) && !(i&(1<<k))) || (!(i&(1<<j)) && i&(1<<k))) ret += mp[j][k];
			}
		}
		if(ret > ans) ans = ret, res = i;
	}
	for(i = 1; i <= n; i++){
		if(res&(1<<num[s[i]-'a'])) s[i] += 'A'-'a';
		printf("%c", s[i]);
	}
	return 0;
}

*D. Dividing Marbles

nike0good的blog,有空研究

E. Equal Numbers

一种是把它乘到它的一个存在的倍数,一种是把它乘到lcm

分开处理这两种情况即可

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int Maxn = 1000010;
int sum[Maxn], n;
int a[Maxn], al, b[Maxn], bl;
int f[Maxn];
int _min(int x, int y) { return x < y ? x : y; }
int main() {
	freopen("equal.in", "r", stdin);
	freopen("equal.out", "w", stdout);
	int i, j, k;
	scanf("%d", &n);
	for(i = 1; i <= n; i++){
		int x;
		scanf("%d", &x);
		sum[x]++;
	}
	int ss = 0;
	for(i = 1; i <= 1000000; i++){
		if(sum[i] > 0){
			bool bk = false;
			for(j = i+i; j <= 1000000; j += i){
				if(sum[j] > 0){ bk = true; break; }
			}
			if(bk == true) a[++al] = sum[i];
			b[++bl] = sum[i];
			ss++;
		}
	}
	memset(f, 63, sizeof(f)); f[0] = ss;
	sort(a+1, a+al+1);
	int su = 0;
	for(i = 1; i <= al; i++){
		su += a[i];
		f[su] = _min(f[su], ss-i);
	}
	sort(b+1, b+bl+1);
	su = 0;
	for(i = 1; i <= bl; i++){
		su += b[i];
		f[su] = _min(f[su], ss-i+1);
	}
	for(i = 0; i <= n; i++){
		if(i) f[i] = _min(f[i], f[i-1]);
		printf("%d%c", f[i], i==n?'\n':' ');
	}
	return 0;
}

*F. Fygon 2.0

留坑

*G. Grand Test

dfs,用反祖边覆盖树边,如果一条树边被覆盖了两次,把这两条反祖边拿出来

然后找度数为$3$的两个点,一定存在三条路径

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int Maxn = 100010;
struct node {
	int x, y, next;
}a[Maxn<<1]; int first[Maxn], len;
void ins(int x, int y) {
	len++;
	a[len].x = x; a[len].y = y;
	a[len].next = first[x]; first[x] = len;
}
int n, m;
int fa[Maxn], bo[Maxn]; bool bk, insta[Maxn];
int dfn[Maxn], id;
int ansk1, ansk2, ansx, ansy;
void dfs(int x) {
	if(!bk) return;
	dfn[x] = ++id; insta[x] = true;
	for(int k = first[x]; k && bk; k = a[k].next){
		int y = a[k].y;
		if(y == fa[x]) continue;
		if(!dfn[y]){
			fa[y] = x; bo[y] = 0;
			dfs(y);
		} else if(insta[y]){
			int p = x;
			while(p != y){
				if(bo[p]){
					bk = false;
					ansk1 = bo[p];
					ansk2 = k;
					break;
				}
				bo[p] = k;
				p = fa[p];
			}
		}
	}
	insta[x] = false;
}
vector <int> vec[Maxn];
queue <int> q;
int pre[Maxn], ans[Maxn], ansl;
int main() {
	freopen("grand.in", "r", stdin);
	freopen("grand.out", "w", stdout);
	int i, j, k;
	int T;
	scanf("%d", &T);
	while(T--){
		scanf("%d%d", &n, &m);
		len = 0; for(i = 1; i <= n; i++) first[i] = 0;
		for(i = 1; i <= m; i++){
			int x, y;
			scanf("%d%d", &x, &y);
			ins(x, y); ins(y, x);
		}
		for(i = 1; i <= n; i++) dfn[i] = 0; id = 0;
		bk = true;
		for(i = 1; i <= n && bk; i++) if(!dfn[i]) fa[i] = 0, dfs(i);
		if(bk == true){ printf("-1\n"); continue; }
		for(i = 1; i <= n; i++) vec[i].clear();
		vec[a[ansk1].x].push_back(a[ansk1].y); vec[a[ansk1].y].push_back(a[ansk1].x);
		vec[a[ansk2].x].push_back(a[ansk2].y); vec[a[ansk2].y].push_back(a[ansk2].x);
		int p = a[ansk1].x;
		while(p != a[ansk1].y){
			vec[p].push_back(fa[p]); vec[fa[p]].push_back(p);
			p = fa[p];
		}
		p = a[ansk2].x;
		while(p != a[ansk2].y){
			if(bo[p] != ansk1) vec[p].push_back(fa[p]), vec[fa[p]].push_back(p);
			p = fa[p];
		}
		ansx = ansy = 0;
		for(i = 1; i <= n; i++){
			if(vec[i].size() == 3){
				if(!ansx) ansx = i;
				else { ansy = i; break; }
			}
		}
		for(i = 1; i <= n; i++) pre[i] = -1;
		printf("%d %d\n", ansx, ansy);
		pre[ansx] = 0;
		q.push(ansx);
		while(!q.empty()){
			int x = q.front(); q.pop();
			for(i = 0; i < vec[x].size(); i++){
				int y = vec[x][i];
				if(pre[y] == -1){
					if(y == ansy){
						ansl = 0; ans[++ansl] = ansy;
						for(j = x; j; j = pre[j]) ans[++ansl] = j;
						printf("%d ", ansl);
						for(j = ansl; j >= 1; j--) printf("%d%c", ans[j], j==1?'\n':' ');
						continue;
					}
					pre[y] = x;
					q.push(y);
				}
			}
		}
	}
	return 0;
}

*H. Hidden Supervisors

对于一棵树总有一种答案最大的方案使得所有不选的点都在叶子节点上

dp根选与不选的最大匹配,发现$f_{i,1}-f_{i,0}\leq 1$

如果$f_{i,1}=f_{i,0}+1$,让根匹配并不会比让根不匹配差,那么直接连到$1$就行了

其他的按照未匹配叶子节点的大小合并就行了

另外只有单独一个点的要特殊考虑

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int Maxn = 100010;
const int inf = 0x7fffffff;
vector <int> vec[Maxn];
int fa[Maxn], n;
int f[Maxn][2], num[Maxn], size[Maxn];
void dfs(int x) {
	size[x] = 1;
	if(vec[x].size() == 0) return;
	int ret1 = -inf; f[x][0] = 0;
	for(int i = 0; i < vec[x].size(); i++){
		int y = vec[x][i];
		dfs(y);
		size[x] += size[y];
		if(!vec[y].size()){
			if(0 > ret1) ret1 = 0, num[x] = y;
		} else {
			f[x][0] += f[y][1];
			if(f[y][0]-f[y][1] > ret1) ret1 = f[y][0]-f[y][1], num[x] = y;
		}
	}
	f[x][1] = f[x][0]+ret1+1;
}
queue <int> q, qu;
void dfs2(int x) {
	for(int i = 0; i < vec[x].size(); i++){
		int y = vec[x][i];
		if(y == num[x]) continue;
		if(!vec[y].size()) q.push(y);
		else dfs2(y);
	}
	for(int i = 0; i < vec[num[x]].size(); i++){
		int y = vec[num[x]][i];
		if(!vec[y].size()) q.push(y);
		else dfs2(y);
	}
}
struct lnode {
	int x, p;
	lnode (int x = 0, int p = 0) : x(x), p(p) {}
	bool operator<(const lnode &A) const { return p > A.p; }
}list[Maxn]; int l;
int main() {
	freopen("hidden.in", "r", stdin);
	freopen("hidden.out", "w", stdout);
	int i, j, k;
	scanf("%d", &n);
	for(i = 2; i <= n; i++){
		scanf("%d", &fa[i]);
		if(fa[i]) vec[fa[i]].push_back(i);
	}
	for(i = 1; i <= n; i++){
		if(!fa[i]) dfs(i);
	}
	int ans = 0;
	if(vec[1].size() == 0) q.push(1);
	else {
		ans += f[1][1];
		dfs2(1);
	}
	for(i = 2; i <= n; i++){
		if(!fa[i]){
			if(!vec[i].size()) qu.push(i);
			else if(f[i][0] < f[i][1]) ans += f[i][1], fa[i] = 1, dfs2(i);
			else list[++l] = lnode(i, size[i]-2*f[i][0]-1);
		}
	}
	sort(list+1, list+l+1);
	for(i = 1; i <= l; i++){
		if(q.empty() && !qu.empty()){
			int x = qu.front();
			fa[x] = 1;
			q.push(x); qu.pop();
		}
		if(!q.empty()){
			int x = q.front(); q.pop();
			fa[list[i].x] = x; ans++;
			ans += f[list[i].x][0];
			for(j = 0; j < vec[list[i].x].size(); j++){
				int y = vec[list[i].x][j];
				if(!vec[y].size()) q.push(y);
				else dfs2(y);
			}
		} else {
			fa[list[i].x] = 1;
			ans += f[list[i].x][1];
			dfs2(list[i].x);
		}
	}
	while(!q.empty() && !qu.empty()){
		int x = q.front(), y = qu.front(); q.pop(); qu.pop();
		fa[y] = x; ans++;
	}
	while(!qu.empty()){
		int x = qu.front(); qu.pop();
		fa[x] = 1;
		if(!qu.empty()){
			int y = qu.front(); qu.pop();
			fa[y] = x; ans++;
		}
	}
	printf("%d\n", ans);
	for(i = 2; i <= n; i++) printf("%d%c", fa[i], i==n?'\n':' ');
}

I. Intelligence in Perpendicularia

就是总长度-在外面能看到的,扫描线+线段树就行了..

*J. Joker

留坑

K. Kotlin Island

枚举行列分多少块即可

L. Little Difference

问题就是要求$a^x+(a+1)^y=n$的方案数

枚举$x$和$y$二分求$a$即可

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define LL long long
using namespace std;
const LL sx = 1e18+100;
LL n;
struct lnode {
	LL x, i, j;
	lnode (LL x = 0, LL i = 0, LL j = 0) : x(x), i(i), j(j) {}
}list[1000010]; LL l;
LL mul(LL x, LL y) {
	if(x > sx/y) return sx;
	x *= y;
	if(x > sx) return sx;
	return x;
}
LL qpow(LL x, LL k) {
	LL ret = 1;
	while(k){
		if(k&1) ret = mul(ret, x);
		x = mul(x, x);
		k >>= 1;
	}
	return ret;
}
bool check(LL x, LL i, LL j) {
	return mul(qpow(x, i), qpow(x+1, j)) <= n;
}
int main() {
	freopen("little.in", "r", stdin);
	freopen("little.out", "w", stdout);
	LL i, j, k;
	scanf("%I64d", &n);
	if((n&(-n)) == n){ printf("-1\n"); return 0; }
	for(i = 0; i <= 59; i++){
		LL p, o;
		if(p = qpow(2, i) > n) break;
		for(j = 1; j <= 31; j++){
			if(mul(p, qpow(3, j)) > n) break;
			LL L = 2, R = n, ret;
			while(L <= R){
				LL mid = L+R>>1;
				if(check(mid, i, j)) ret = mid, L = mid+1;
				else R = mid-1;
			}
			if(mul(qpow(ret, i), qpow(ret+1, j)) == n) list[++l] = lnode(ret, i, j);
		}
	}
	printf("%I64d\n", l);
	for(i = 1; i <= l; i++){
		printf("%I64d", list[i].i+list[i].j);
		while(list[i].i--) printf(" %I64d", list[i].x);
		while(list[i].j--) printf(" %I64d", list[i].x+1);
		printf("\n");
	}
	return 0;
}

 

posted @ 2017-12-26 15:28 Ra1nbow 阅读(...) 评论(...) 编辑 收藏