ARC105
来了,老年选手感到自己水平有一点差劲
A - Fourtune Cookies
题意:给四块饼干问能不能分成总和相同的两份
二进制枚举就行
#include <bits/stdc++.h>
#define fi first
#define se second
//#define ivorysi
#define enter putchar('
')
#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('
')
#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('
')
#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('
')
#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('
')
#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需要特判输出)
(Nleq 17)考虑状压
连通性考虑经典容斥:枚举1所在的连通块组成,然后乘上剩余部分的方案,是需要消去的
首先我们考虑染色统计二分图个数(也就是一个点算成黑点和白点是两种方案),并通过容斥强行保证二分图的每个点都有连边
设(g[S])为点集S染色黑白后黑点和白点都有边连的方案数,初始化是两个点如果有边(g[S] = 2)
然后枚举(S)的子集(T),减去(g[T] imes 2^{cnt[S oplus T]})(因为没连边的的点可能染黑或者染白)
之后计算(f[S])为连通的染色二分图方案数,计算方法为枚举子集(T)(要保证T里有1),减去(f[T] imes g[S oplus T])
为了消除染色的影响要除2
#include <bits/stdc++.h>
#define fi first
#define se second
//#define ivorysi
#define enter putchar('
')
#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;
}