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;
}