T1
// 應該是 Topcoder 的題,但是實在搜不到,題目名太不具有辨識度
設每個朝代與標準紀年法的距離為 \(x_i\),則每個約束條件相當於限制了某兩個 \(x_i\) 之間的差。查詢的時候也假設查詢的那場戰爭發生,同樣視為限制。按照差分約束建出圖,如果圖中存在負環說明新加的這個限制會導致不等式組無解,也就是這場戰爭不可能發生。我這裡使用了 Bellman-Ford 判負環,spfa 當然也行。
程式碼
#include <iostream>
#include <string.h>
#include <cassert>
using namespace std;
int n;
int mcnt[30];
int l[30][15], r[30][15];
struct Edge {
int u, v, w;
} E[200005];
int ecnt;
inline bool isUpper(char x) { return 'A' <= x && x <= 'Z'; }
inline bool isDigit(char x) { return '0' <= x && x <= '9'; }
void Deal(string s) {
assert(s[0] != ' ');
int ax = s[0] - 'A' + 1;
int ay = s[1] - '0' + 1;
int bx = s[3] - 'A' + 1;
int by = s[4] - '0' + 1;
int l1 = l[ax][ay], r1 = r[ax][ay];
int l2 = l[bx][by], r2 = r[bx][by];
E[++ecnt] = (Edge) { bx, ax, r2 - l1 };
E[++ecnt] = (Edge) { ax, bx, r1 - l2 };
}
void ini() {
int m;
cin >> m;
m++;
getchar();
string str;
while (m--) {
string s;
getline(cin, s);
str += s;
}
string tmp;
for (int i = 0; i < (int)str.size(); i++) {
if (isUpper(str[i]) || isDigit(str[i]) || str[i] == '-')
tmp += str[i];
if (tmp.size() == 5) {
Deal(tmp);
tmp = "";
}
}
}
int dist[30];
bool NegaCycle() {
memset(dist, 63, sizeof dist);
bool upd = 0;
dist[1] = 0;
for (int i = 0; i <= n; i++) {
upd = 0;
for (int j = 1; j <= ecnt; j++) {
if (dist[E[j].v] > dist[E[j].u] + E[j].w)
dist[E[j].v] = dist[E[j].u] + E[j].w, upd = 1;
}
}
return upd;
}
string sss;
int main() {
cin >> n;
getline(cin, sss);
for (int i = 1; i <= n; i++) {
string str;
getline(cin, str);
str += ' ';
int cur = 0;
for (int j = 0; j < (int)str.size(); j++) {
if (isDigit(str[j]))
cur = cur * 10 + str[j] - '0';
else {
l[i][++mcnt[i]] = cur;
r[i][mcnt[i] - 1] = cur - 1;
cur = 0;
}
}
}
ini();
int q;
cin >> q;
while (q--) {
string str;
cin >> str;
Deal(str);
cout << (NegaCycle() ? "N" : "Y");
ecnt -= 2;
}
cout << "\n";
return 0;
}
T3
Topcoder SRM 561 div1 Medium - CirclesGame
首先發現圓之間的包含關係會構成一棵樹。每次操作相當於選一個節點,封掉這個節點到根路徑上的所有點。不能操作者輸。直接考慮博弈論。狀態就是某棵子樹,然後觀察到一個狀態的某個後繼狀態就是在這個子樹中選出一個點,然後把這個點到這棵子樹的根上的點全部刪掉所形成的所有連通塊。會發現這其實是遞迴的一個組合博弈遊戲。我們求出所有這些連通塊的 SG 函式值,然後把它們異或起來就可以得到這個後繼狀態的 SG 函式值。然後再對這個狀態列舉其所有後繼狀態,把這些後繼狀態的 SG 值取 mex 即為當前狀態的 SG。最後把所有連通塊的 SG 異或起來看是不是 \(0\) 就好了。
程式碼
#include <iostream>
#include <algorithm>
#include <cassert>
#define int long long
using namespace std;
int n;
struct C {
int x, y, r;
} a[200005];
bool chk(int i, int j) { // a in b
return (a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y) <= (a[i].r - a[j].r) * (a[i].r - a[j].r) && a[i].r < a[j].r;
}
int head[5005], to[200005], nxt[200005], ecnt;
void add(int u, int v) { to[++ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt; }
int in[5005];
int L[5005], ncnt, R[5005];
int _dfn[5005];
int fa[5005];
void dfs1(int x) {
_dfn[L[x] = ++ncnt] = x;
for (int i = head[x]; i; i = nxt[i]) {
fa[to[i]] = x;
dfs1(to[i]);
}
R[x] = ncnt;
}
int f[5005];
bool vis[5005];
int cnt[10005];
void dfs2(int x) {
for (int i = head[x]; i; i = nxt[i]) {
int v = to[i];
dfs2(v);
}
for (int i = L[x]; i <= R[x]; i++) {
int tmp = 0;
int v = _dfn[i], lst = -1;
while (v != fa[x]) {
for (int j = head[v]; j; j = nxt[j]) {
if (to[j] != lst)
tmp ^= f[to[j]];
}
lst = v;
v = fa[v];
}
cnt[tmp]++;
}
for (int i = 0; i <= 1000; i++) {
if (cnt[i] == 0) {
f[x] = i;
break;
}
}
for (int i = 0; i <= 1000; i++) cnt[i] = 0;
}
int g[505][505];
signed main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i].x;
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i].y;
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i].r;
sort(a + 1, a + n + 1, [](C a, C b) { return a.r > b.r; });
for (int i = 1; i <= n; i++) {
for (int j = i - 1; j; j--) {
if (chk(i, j)) {
add(j, i);
in[i]++;
break;
}
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
if (!in[i]) {
dfs1(i);
dfs2(i);
ans ^= f[i];
}
}
cout << (ans ? "Alice" : "Bob") << "\n";
return 0;
}