题目链接
A. Fox And Snake
蛇形填数,C语言基础问题。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
int N, M;
char mp[55][55];
int main()
{
scanf("%d%d", &N, &M);
for(int i=0; i<N; i+=2)
{
for(int j=0; j<M; j++) mp[i][j] = '#';
}
for(int i=1; i<N; i+=4)
{
for(int j=0; j<M-1; j++) mp[i][j] = '.';
mp[i][M - 1] = '#';
}
for(int i=3; i<N; i+=4)
{
for(int j=1; j<M; j++) mp[i][j] = '.';
mp[i][0] = '#';
}
for(int i=0; i<N; i++) printf("%s\n", mp[i]);
return 0;
}
B. Fox And Two Dots
DFS。
这题稍微卡了一会,是因为一开始想既然要构成环的话,那么是否可以用并查集来维护,如果判断到相等的时候就是直接Yes了?但是显然存在一个问题,就是你不知道你是怎样走的,于是我想了下,我似乎可以用dfs来跑深度,这样,如果跑到一个深度和毗邻的点的深度差大于等于3的时候并且还是同一种颜色的,就一定是构成了size大于等于4的环了。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 55;
const int dir[4][2] =
{
-1, 0,
0, -1,
0, 1,
1, 0
};
int N, M, _UP, root[maxN * maxN];
inline int _id(int x, int y) { return (x - 1) * M + y; }
char mp[maxN][maxN];
int fid(int x) { return x == root[x] ? x : root[x] = fid(root[x]); }
pair<int, int> it;
vector<pair<int, int>> vt[27];
inline bool In_map(int x, int y) { return x >= 1 && y >= 1 && x <= N && y <= M; }
struct node
{
int x, y, step;
node(int a=0, int b=0, int c=0):x(a), y(b), step(c) {}
};
queue<node> Q;
int vis[maxN][maxN] = {0};
bool check_OK(int sx, int sy, int xx, int yy)
{
if(sx == xx && abs(sy - yy) == 1)
{
if(mp[sx][sy] == mp[xx][yy] && abs(vis[sx][sy] - vis[xx][yy]) >= 3) return true;
}
else if(sy == yy && abs(xx - sx) == 1)
{
if(mp[sx][sy] == mp[xx][yy] && abs(vis[sx][sy] - vis[xx][yy]) >= 3) return true;
}
return false;
}
bool OK = false;
int SX, SY;
void dfs(int sx, int sy, int deep)
{
for(int i=0, xx, yy; i<4; i++)
{
xx = sx + dir[i][0]; yy = sy + dir[i][1];
if(!In_map(xx, yy)) continue;
if(mp[sx][sy] ^ mp[xx][yy]) continue;
if(vis[xx][yy])
{
if(check_OK(sx, sy, xx, yy))
{
OK = true;
return;
}
continue;
}
vis[xx][yy] = deep + 1;
dfs(xx, yy, deep + 1);
if(OK) return;
}
}
int main()
{
scanf("%d%d", &N, &M);
_UP = N * M;
for(int i=1; i<=_UP; i++) root[i] = i;
for(int i=1, col; i<=N; i++)
{
scanf("%s", mp[i] + 1);
for(int j=1; j<=M; j++)
{
col = mp[i][j] - 'A';
vt[col].push_back(MP(i, j));
}
}
for(int i=0, len; i<26; i++)
{
len = (int)vt[i].size();
for(int j=0; j<len; j++)
{
it = vt[i][j];
if(vis[it.first][it.second]) continue;
SX = it.first; SY = it.second;
vis[SX][SY] = 1;
dfs(it.first, it.second, 1);
if(OK) { printf("Yes\n"); return 0; }
}
}
printf("No\n");
return 0;
}
这题代码写的不是很好,因为训练赛的时候一开始想了跑Tarjan还有各种玄学东西来弄,但是都没有考虑到无向的这一层面,如果建无向图Tarjan又不好确定size,所以最后想到了dfs这个玄学的存在。
C. Fox And Names
拓扑排序
题意的这层描叙,简直就是差把“这就是到拓扑,建边跑吧”给说出来了。很显然,由于这里的N很小,字符串的长度也是很小,我们在字符串比较上甚至不需要过多的优化操作,我们可以利用如此的暴力解法来解决问题。然后建了边之后直接拓扑即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 105;
int N, len[maxN];
char s[maxN][maxN];
int head[30], cnt, du[30] = {0};
struct Eddge
{
int nex, to;
Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN * maxN];
inline void addEddge(int u, int v)
{
edge[cnt] = Eddge(head[u], v);
head[u] = cnt++;
}
int _Index[maxN] = {0}, tot;
char ans[30];
queue<int> Q;
void tp_sort()
{
for(int i=0; i<26; i++)
{
if(!du[i]) Q.push(i);
}
int u;
while(!Q.empty())
{
u = Q.front(); Q.pop();
_Index[u] = ++tot;
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
du[v]--;
if(du[v] == 0) Q.push(v);
}
}
}
inline void init()
{
cnt = 0;
for(int i=0; i<26; i++) head[i] = -1;
}
int main()
{
scanf("%d", &N);
init();
for(int i=1; i<=N; i++) scanf("%s", s[i] + 1);
for(int i=1; i<=N; i++) len[i] = (int)strlen(s[i] + 1);
bool flag = true;
for(int i=1, u, v, min_len; i<=N; i++)
{
for(int j=i + 1; j<=N; j++)
{
min_len = min(len[i], len[j]);
for(int k=1; k<=min_len; k++)
{
if(s[i][k] == s[j][k]) //相等的情况
{
if(k == min_len && len[i] > len[j]) flag = false; //如果是到了最后一位了
continue;
}
u = s[i][k] - 'a'; v = s[j][k] - 'a';
addEddge(u, v);
du[v]++;
break;
}
}
}
if(!flag) { printf("Impossible\n"); return 0; }
tp_sort();
for(int i=0; i<26; i++)
{
if(!_Index[i]) { flag = false; break; }
}
if(!flag) { printf("Impossible\n"); return 0; }
for(int i=0; i<26; i++) ans[_Index[i]] = 'a' + i;
for(int i=1; i<=26; i++) printf("%c", ans[i]);
printf("\n");
return 0;
}
D. Fox And Jumping
DP
还是挺好的一道DP,主要是我们在【x - L, x + L】这里的想法,首先我们想由几种Li来构成任意的1,这里可以想到,我们可以用gcd来维护。也就是,我们需要取一部分的Li使得最后的合成gcd为1,并且呢,花费还是最小的。
那么,可以用一个背包DP来做,我们有N个数它们都有对应的价值,所以的话,我们可以一一放入,并且更新gcd,但是为了维护起来方便一点,我定义了当目前为0的时候,需要的花费为0,因为gcd(x, 0) = 0这是我们gcd()的写法。
再者,这里是不能用unordered_map的,因为它是对于第一维直接哈希Hash了,众所周知,我们是不能对一个Hash过了的值进行一些其他的操作了的。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 305;
int N, c[maxN], L[maxN];
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
map<int, int> dp;
map<int, int>::iterator it;
int main()
{
scanf("%d", &N);
for(int i=1; i<=N; i++) scanf("%d", &L[i]);
for(int i=1; i<=N; i++) scanf("%d", &c[i]);
dp[0] = 0;
for(int i=1, val, cost, nex_val, nex_c; i<=N; i++)
{
for(it = dp.begin(); it != dp.end(); it++)
{
val = it->first; cost = it->second;
nex_val = gcd(val, L[i]);
nex_c = cost + c[i];
if(!dp.count(nex_val)) dp[nex_val] = nex_c;
else if(dp[nex_val] > nex_c) dp[nex_val] = nex_c;
}
}
if(!dp.count(1)) printf("-1\n");
else printf("%d\n", dp[1]);
return 0;
}
E. Fox And Dinner
利用网络流最大流解决(大于等于)三元环的环的构造问题。
首先,如果去跑KM等等的二分图上的直接的操作自然是不对的,因为一个点必须要匹配两个点,这就是大于等于三元环的环的解决方式,所以一直很懵,该怎样解决这个问题呢?
然后的话,想的办法就是网络流的最大流了,我们知道,如果一个点在三元环内的话,那么它出去的点是唯一的,进来的点也是唯一的,但是它的度是二。我们反思一下KM的最大(单位)权匹配(匈牙利算法),是可以解决环构造的(解决单位环(可以直接从二元开始)、二元环、三元环……),但是我们现在是必须要从三元环起步。
根据性质,我们现在要做一些改变了。
现在,我们找一下规律,如果它是奇数,那么跟它匹配的点一定就是偶数了,如果它是偶数,那么能与它匹配的点一定也就是奇数了,所以,有了这一条性质之后,我们现在可以把图拆成一个二分图了,左边是奇数值的点,右边是偶数值的点,然后再看,我们打个预处理的质数筛,我们就可以把对应的关系给列出来了,流为单位一。
然后呢,因为每个点的出度都是2,所以呢,从源点到奇数点的流为2,偶数点到汇点的流为2,就可以保证我们所构成的环一定是个大于等于三元环的。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 205, S = 0;
int N, a[maxN], flow[maxN][maxN] = {0}, T;
struct Prim_num
{
bool Prim[20005];
Prim_num()
{
memset(Prim, true, sizeof(Prim));
for(int i=2; i<=20000; i++)
{
if(Prim[i])
{
for(int j=2 * i; j<=20000; j+=i)
{
Prim[j] = false;
}
}
}
}
inline void solve()
{
}
}PP;
int deep[maxN] = {0};
inline bool bfs()
{
queue<int> Q;
for(int i=0; i<=T; i++) deep[i] = 0;
deep[S] = 1; Q.push(S);
while(!Q.empty())
{
int u = Q.front(); Q.pop();
for(int i=0; i<=T; i++)
{
if(flow[u][i] && !deep[i])
{
deep[i] = deep[u] + 1;
Q.push(i);
}
}
}
return deep[T];
}
int dfs(int u, int dist)
{
if(u == T) return dist;
for(int i=0, di; i<=T; i++)
{
if(deep[u] + 1 == deep[i] && flow[u][i])
{
di = dfs(i, min(dist, flow[u][i]));
if(di)
{
flow[u][i] -= di; flow[i][u] += di;
return di;
}
}
}
return 0;
}
int Dinic()
{
int ans = 0, tmp;
while(bfs())
{
while((tmp = dfs(S, N))) ans += tmp;
}
return ans;
}
vector<int> nex[maxN];
bool vis[maxN] = {false};
vector<int> vt;
vector<vector<int>> ans;
inline void solve()
{
for(int i=1; i<=N; i++)
{
if((a[i] & 1) == 0) continue;
for(int j=1; j<=N; j++)
{
if(a[j] & 1) continue;
if(!PP.Prim[a[i] + a[j]]) continue;
if(!flow[i][j])
{
nex[i].push_back(j);
nex[j].push_back(i);
}
}
}
for(int i=1; i<=N; i++)
{
if(vis[i]) continue;
vis[i] = true;
vt.clear();
vt.push_back(i);
int now = nex[i][0];
while(!vis[now])
{
vt.push_back(now);
vis[now] = true;
if(vis[nex[now][0]]) now = nex[now][1];
else now = nex[now][0];
}
ans.push_back(vt);
}
int len = (int)ans.size();
printf("%d\n", len);
for(int i=0, siz; i<len; i++)
{
siz = (int)ans[i].size();
printf("%d", siz);
for(int j=0; j<siz; j++) printf(" %d", ans[i][j]);
printf("\n");
}
}
int main()
{
scanf("%d", &N);
T = N + 1;
for(int i=1; i<=N; i++)
{
scanf("%d", &a[i]);
if(a[i] & 1) flow[S][i] = 2;
else flow[i][T] = 2;
}
for(int i=1; i<=N; i++)
{
if((a[i] & 1) == 0) continue;
for(int j=1; j<=N; j++)
{
if(a[j] & 1) continue;
if(!PP.Prim[a[i] + a[j]]) continue;
flow[i][j] = 1;
}
}
int Max_Flow = Dinic();
if(Max_Flow ^ N) { printf("Impossible\n"); return 0; }
solve();
return 0;
}