【AtCoder】ARC105

ARC105

来了,老年选手感到自己水平有一点差劲

A - Fourtune Cookies

题意:给四块饼干问能不能分成总和相同的两份

二进制枚举就行

#include <bits/stdc++.h>
#define fi first
#define se second
//#define ivorysi
#define enter putchar('\n')
#define space putchar(' ')

#define pii pair<int,int>
typedef long long int64;
using namespace std;

template<class T>
void read(T &res) {
	res = 0;T f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		res = res * 10 + c - '0';
		c = getchar();
	}
	res *= f;
}
template<class T>
void out(T x) {
	if(x < 0) {x = -x;putchar('-');}
	if(x >= 10) out(x / 10);
	putchar('0' + x % 10);
}
int a[10];
int main() {
#ifdef ivorysi
	freopen("f1.in","r",stdin);
#endif
	int sum = 0;
	for(int i = 0 ; i < 4 ; ++i) {
		read(a[i]);
		sum += a[i];
	}
	for(int S = 1 ; S < (1 << 4) ; ++S) {
		int s = 0;
		for(int i = 0 ; i < 4 ; ++i) {
			if(S & (1 << i)) s += a[i];
		}
		if(s == sum - s) {
			puts("Yes");
			return 0;
		}
	}
	puts("No");
	return 0;
}

B - MAX-=min

题意:每次把最大值全部替换成(最大值-最小值),问最后剩下的数

可以想到最大值为\(M\)最小值为\(m\),如果\(M > 2m\),那么\(M\)会不断变小,而\(M - m <= m\),最大值总在不断变小

这其实是取余,一堆数不断互相取余最后剩下的就是这些数的最大公约数

#include <bits/stdc++.h>
#define fi first
#define se second
//#define ivorysi
#define enter putchar('\n')
#define space putchar(' ')

#define pii pair<int,int>
typedef long long int64;
using namespace std;

template<class T>
void read(T &res) {
	res = 0;T f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		res = res * 10 + c - '0';
		c = getchar();
	}
	res *= f;
}
template<class T>
void out(T x) {
	if(x < 0) {x = -x;putchar('-');}
	if(x >= 10) out(x / 10);
	putchar('0' + x % 10);
}
int a[100005],N;
int gcd(int a,int b) {
	return b == 0 ? a : gcd(b, a % b);
}
int main() {
#ifdef ivorysi
	freopen("f1.in","r",stdin);
#endif
	read(N);

	for(int i = 1 ; i <= N ; ++i) {
		read(a[i]);
	}
	int t = a[1];
	for(int i = 2 ; i <= N ; ++i) {
		t = gcd(t,a[i]);
	}
	out(t);enter;
	return 0;
}

C - Camels and Bridge

题意:一个桥有\(M\)段,每个段有长度\(l_{i}\)和容量\(v_{i}\),有\(N\)个骆驼每只体重为\(w_{i}\),问这些骆驼第一个到最后一个最小距离是多少

因为\(N\)很小,相对顺序全排列暴力枚举,然后枚举\(i,j\)\(i\)\(j\)的骆驼重量总和为\(V\),那么容量小于\(V\)的桥最小距离是多少,这个可以二分和前缀取max解决

#include <bits/stdc++.h>
#define fi first
#define se second
//#define ivorysi
#define enter putchar('\n')
#define space putchar(' ')

#define pii pair<int,int>
typedef long long int64;
using namespace std;

template<class T>
void read(T &res) {
	res = 0;T f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		res = res * 10 + c - '0';
		c = getchar();
	}
	res *= f;
}
template<class T>
void out(T x) {
	if(x < 0) {x = -x;putchar('-');}
	if(x >= 10) out(x / 10);
	putchar('0' + x % 10);
}
const int MAXM = 100005;
int N,M;
int64 w[10],l[MAXM],v[MAXM],ans,sum[10],dis[10][10],dp[10];
int64 val[MAXM],len[MAXM];
int a[10],id[MAXM];
bool vis[10];
void dfs(int d) {
	if(d > N) {
		for(int i = 1 ; i <= N ; ++i) {
			sum[i] = sum[i - 1] + w[a[i]];
		}
		memset(dis,0,sizeof(dis));
		for(int j = 1 ; j <= N ; ++j) {
			for(int t = j + 1 ; t <= N ; ++t) {
				int cv = sum[t] - sum[j - 1];
				int p = lower_bound(val + 1,val + M + 1,cv) - val - 1;
				if(val[p] < cv) {
					dis[j][t] = len[p];
				}
			}
		}
		memset(dp,0,sizeof(dp));
		for(int i = 1 ; i <= N ; ++i) {
			for(int j = i + 1 ; j <= N ; ++j) {
				dp[j] = max(dp[j],dp[i] + dis[i][j]);
			}
		}
		ans = min(ans, dp[N]);
		return;
	}
	for(int i = 1 ; i <= N ; ++i) {
		if(!vis[i]) {
			a[d] = i;
			vis[i] = 1;
			dfs(d + 1);
			vis[i] = 0;
		}
	}
}
int main() {
#ifdef ivorysi
	freopen("f1.in","r",stdin);
#endif
	read(N);read(M);
	for(int i = 1 ; i <= N ; ++i) read(w[i]);
	for(int i = 1 ; i <= M ; ++i) {
		read(l[i]);read(v[i]);
		id[i] = i;
		ans += l[i];
	}
	ans = ans * N;
	sort(id + 1,id + M + 1,[](int a,int b) {return v[a] < v[b] || (v[a] == v[b] && l[a] > l[b]);});
	for(int i = 1 ; i <= M ; ++i) {
		val[i] = v[id[i]];
		len[i] = l[id[i]];
		len[i] = max(len[i],len[i - 1]);
	}
	for(int i = 1 ; i <= M ; ++i) {
		for(int j = 1 ; j <= N ; ++j) {
			if(w[j] > v[i]) {
				puts("-1");
				return 0;
			}
		}
	}
	dfs(1);
	out(ans);enter;
	return 0;
}

D - Let's Play Nim

有N个包,包里有\(a_i\)个硬币,有\(N\)个盘子,第一阶段先后手轮流拿一个包,然后把包里的钱全倒在任意一个盘子里,第二阶段开始对盘子里的硬币做“一次可以取一个盘子里一个或任意多个,不能取者输的nim游戏”

考虑第二阶段的nim,只有异或和为0这种情况后手可以赢,然而如果不是所有包可以按硬币两两配对的话,想让异或和不为0的一方总有办法让一个盘子里的东西大于\(\frac{sum\{a_{i}\}}{2}\)

而这种情况下, 由于异或是按位消去,那么如果异或和为0,剩余物品的容量综合应该大于等于\(\frac{sum\{a_{i}\}}{2}\)于是得到矛盾

那么想让异或和不为0的一方在不是所有包可以按硬币两两配对的情况下总可以赢,所以就直接判断第一阶段后谁先手就行了

#include <bits/stdc++.h>
#define fi first
#define se second

//#define ivorysi
#define enter putchar('\n')
#define space putchar(' ')
#define pii pair<int,int>
#define MOD 998244353
#define MAXN 100005
typedef long long int64;
using namespace std;

template<class T>
void read(T &res) {
	res = 0;T f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		res = res * 10 + c - '0';
		c = getchar();
	}
	res *= f;
}
template<class T>
void out(T x) {
	if(x < 0) {x = -x;putchar('-');}
	if(x >= 10) out(x / 10);
	putchar('0' + x % 10);
}

int T,N,a[MAXN];
string nm[2] = {"First","Second"};
void Solve() {
	read(N);
	for(int i = 1 ; i <= N ; ++i) {
		read(a[i]);
	}
	sort(a + 1,a + N + 1);
	int t = 0;t ^= (N & 1);
	if(N % 2 == 0) {
		bool f = 1;
		for(int i = N ; i >= 1 ; i -= 2) {
			if(a[i] != a[i - 1]) {f = 0;break;}
		}
		t ^= f;
	}
	cout << nm[t] << endl;
}
int main() {
#ifdef ivorysi
	freopen("f1.in","r",stdin);
#endif
	read(T);
	while(T--) {
		Solve();
	}
	return 0;
}

E - Keep Graph Disconnected

题意:一个\(N\)个点的图\(1\)\(N\)不联通,先后手给图加边,要保证\(1,N\)不连通,不能加边者输

如果\(1\)的连通块为\(x\),而\(N\)所在的连通块为\(y\),答案和\(\frac{N(N - 1)}{2} - xy - M\)的奇偶性有关

而若\(N\)为奇数,那么\(n(N - n)\)一定是偶数,那么胜负固定

如果\(N\)为偶数,那么如果\(x,y\)奇偶性不同,先手总有办法让\(x,y\)变成自己想要的奇偶性

例如先手希望是偶数,就找一个奇数块连到\(x,y\)中为奇数的那一边

例如先手希望是奇数,就找一个奇数块连到\(x,y\)是偶数的那一边

因为总和为偶数,后手想用奇数块变\(x,y\)的奇偶性,先手总可以跟一步

如果\(x,y\)的奇偶性相同,\(xy\)为奇数或者偶数

希望是奇数/偶数的那一方,总有策略让\(xy\)奇偶性不变(考虑如果\(xy\)满足我的要求了,这一步我就把两个奇数块连成一个偶数块,若全场只剩偶数块那对方变不了我的奇偶性,若不满足我要求,我总可以拿一个奇数块变回去)

#include <bits/stdc++.h>
#define fi first
#define se second

//#define ivorysi
#define enter putchar('\n')
#define space putchar(' ')

#define pii pair<int,int>
typedef long long int64;
using namespace std;

template<class T>
void read(T &res) {
	res = 0;T f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		res = res * 10 + c - '0';
		c = getchar();
	}
	res *= f;
}
template<class T>
void out(T x) {
	if(x < 0) {x = -x;putchar('-');}
	if(x >= 10) out(x / 10);
	putchar('0' + x % 10);
}
const int MAXN = 100005;
int T,N,M;
int a[MAXN],b[MAXN],fa[MAXN],siz[MAXN];
string nm[2];
int getfa(int u) {
	return fa[u] == u ? u : fa[u] = getfa(fa[u]);
}
void merge(int u,int v) {
	u = getfa(u);v = getfa(v);
	if(u == v) return;
	siz[u] += siz[v];
	fa[v] = u;
}
int main() {
#ifdef ivorysi
	freopen("f1.in","r",stdin);
#endif
	read(T);
	nm[1] = "First";nm[0] = "Second";
	while(T--) {
		read(N);read(M);
		int u,v;
		for(int i = 1 ; i <= N ; ++i) fa[i] = i,siz[i] = 1;
		for(int i = 1 ; i <= M ; ++i) {
			read(u);read(v);
			merge(u,v);
		}
		int s = (1LL * N * (N - 1) / 2 - M) & 1;
		if(N & 1) {
			cout << nm[s] << endl;
		}
		else{
			int t0 = siz[getfa(1)] & 1,t1 = siz[getfa(N)] & 1;
			if(t0 ^ t1) {
				cout << nm[1] << endl;
			}
			else {
				cout << nm[s ^ t0] << endl;
			}
		}
	}
	return 0;
}

F - Lights Out on Connected Graph

题意:将图\(G\)\(M\)条边任意删除或保留,这\(2^{M}\)个生成子图中二分连通图的个数

(注意N=1需要特判输出)

\(N\leq 17\)考虑状压

连通性考虑经典容斥:枚举1所在的连通块组成,然后乘上剩余部分的方案,是需要消去的

首先我们考虑染色统计二分图个数(也就是一个点算成黑点和白点是两种方案),并通过容斥强行保证二分图的每个点都有连边

\(g[S]\)为点集S染色黑白后黑点和白点都有边连的方案数,初始化是两个点如果有边\(g[S] = 2\)

然后枚举\(S\)的子集\(T\),减去\(g[T]\times 2^{cnt[S \oplus T]}\)(因为没连边的的点可能染黑或者染白)

之后计算\(f[S]\)为连通的染色二分图方案数,计算方法为枚举子集\(T\)(要保证T里有1),减去\(f[T] \times g[S \oplus T]\)

为了消除染色的影响要除2

#include <bits/stdc++.h>
#define fi first
#define se second

//#define ivorysi
#define enter putchar('\n')
#define space putchar(' ')
#define pii pair<int,int>
#define MOD 998244353
typedef long long int64;
using namespace std;

template<class T>
void read(T &res) {
	res = 0;T f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		res = res * 10 + c - '0';
		c = getchar();
	}
	res *= f;
}
template<class T>
void out(T x) {
	if(x < 0) {x = -x;putchar('-');}
	if(x >= 10) out(x / 10);
	putchar('0' + x % 10);
}
const int MAXS = (1 << 17) + 5;
int N,M;
int E[20],sum[MAXS],g[MAXS],f[MAXS],cnt[MAXS],pw[405];
int lowbit(int x) {
	return x & (-x);
}
int mul(int a,int b) {
	return 1LL * a * b % MOD;
}
int inc(int a,int b) {
	return a + b >= MOD ? a + b - MOD : a + b;
}
int fpow(int x,int c) {
	int res = 1,t = x;
	while(c) {
		if(c & 1) res = mul(res,t);
		t = mul(t,t);
		c >>= 1;
	}
	return res;
}
void update(int &x,int y) {
	x = inc(x,y);
}
int main() {
#ifdef ivorysi
	freopen("f1.in","r",stdin);
#endif
	read(N);read(M);
	if(N == 1) {
		out(1);enter;return 0;
	}
	int u,v;
	for(int S = 1 ; S < (1 << N) ; ++S) cnt[S] = cnt[S - lowbit(S)] + 1;
	for(int i = 1 ; i <= M ; ++i) {
		read(u);read(v);
		E[u] |= (1 << v - 1);
		E[v] |= (1 << u - 1);
	}
	pw[0] = 1;
	for(int i = 1 ; i <= M ; ++i) pw[i] = mul(pw[i - 1],2);
	for(int S = 1 ; S < (1 << N) ; ++S) {
		for(int i = 1 ; i <= N ; ++i) {
			if(S >> (i - 1) & 1) {
				sum[S] += cnt[S & E[i]];
			}
		}
		sum[S] /= 2;
	}
	for(int S = 1 ; S < (1 << N) ; ++S) {
		if(cnt[S] >= 2) {
			if(cnt[S] == 2)  {
				if(sum[S] == 1)g[S] = 2;
			}
			else {
				int res = 0;
				for(int T = (S - 1) & S; T ; T = (T - 1) & S) {
					int num = sum[S] - sum[T] - sum[S ^ T];
					update(res,pw[num] - 1);
					update(res,MOD - mul(g[T],pw[cnt[S ^ T]]));
				}
				g[S] = res;
			}
		}
	}
	for(int S = 1 ; S < (1 << N - 1) ; ++S) {
		int rS = S << 1 | 1;
		f[rS] = g[rS];
		for(int T = S ; T ; T = (T - 1) & S) {
			int rT = T << 1 | 1;
			int rM = (S ^ T) << 1;
			update(f[rS],MOD - mul(f[rT],g[rM]));
		}
	}
	out(mul(f[(1 << N) - 1],fpow(2,MOD - 2)));enter;
	return 0;
}

posted @ 2020-10-14 22:53  sigongzi  阅读(627)  评论(1编辑  收藏  举报