A
模拟
B
D P \mathcal{DP} DP
C
我们将一个格子看成三元组
(
i
,
j
,
a
i
,
j
)
(i,j,a_{i,j})
(i,j,ai,j)
那么
I
I
I 就相当于是将所有
(
x
,
y
,
z
)
(x,y,z)
(x,y,z) 变成
(
x
,
z
,
y
)
(x,z,y)
(x,z,y)
我们维护一下三维的置换,对平移打上标记就可以了
#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
cs int N = 1e3 + 50, M = 1e5 + 50;
int T, n, m, a[N][N], b[N][N];
int s[3], c[3]; char str[M];
void Main(){
cin >> n >> m;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
scanf("%d", &a[i][j]), --a[i][j];
for(int i = 0; i < 3; i++)
s[i] = 0, c[i] = i;
scanf("%s", str);
for(int i = 0; i < m; i++){
if(str[i] == 'L') --s[1];
if(str[i] == 'R') ++s[1];
if(str[i] == 'U') --s[0];
if(str[i] == 'D') ++s[0];
if(str[i] == 'I') swap(c[1], c[2]), swap(s[1], s[2]);
if(str[i] == 'C') swap(c[0], c[2]), swap(s[0], s[2]);
}
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++){
int t[3]; t[0] = i, t[1] = j, t[2] = a[i][j];
int x = t[c[0]], y = t[c[1]], z = t[c[2]];
x = ((x + s[0]) % n + n) % n;
y = ((y + s[1]) % n + n) % n;
z = ((z + s[2]) % n + n) % n; b[x][y] = z;
}
for(int i = 0; i < n; i++, puts(""))
for(int j = 0; j < n; j++)
cout << b[i][j] + 1 << " "; puts("");
}
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> T;
while(T--) Main();
return 0;
}
D
考虑将
0
0
0 看成
(
x
,
x
+
1
)
(x,x+1)
(x,x+1) 连边,
1
1
1 看成
(
x
,
x
−
1
)
(x,x-1)
(x,x−1) 连边
注意到反转一个子串相当于是将一条欧拉回路倒过来走
题目要求我们尽量向右走,我们每一步维护一下能不能向右走就可以了
#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
cs int N = 1e6 + 50;
int T, n; char S[N];
int a[N], b[N];
void Main(){
scanf("%s", S + 1);
n = strlen(S + 1);
for(int i = 1, s = n; i <= n; i++){
if(S[i] == '0') ++a[s], ++s;
if(S[i] == '1') ++b[s], --s;
} int t = n;
while(true){
bool ok = a[t] && (b[t + 1] || !b[t]);
if(ok) putchar('0'), --a[t], ++t;
else if(b[t]) putchar('1'), --b[t], --t;
else break;
} puts("");
}
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> T;
while(T--) Main();
return 0;
}
E
将原问题放到二维平面上
不妨求出
f
x
,
y
∈
{
0
,
1
}
f_{x,y}\in\{0,1\}
fx,y∈{0,1} 表示每个点是必败还是必胜
那么我们知道若
(
x
,
y
)
(x,y)
(x,y) 左边和下面都为
1
1
1 那么它为
0
0
0
同时
(
x
+
δ
,
y
+
δ
)
(x+\delta,y+\delta)
(x+δ,y+δ) 为可能为
1
1
1 的点,每行每列只可能有一个点为
1
1
1
于是我们设计一个算法:若当前为关键点,那么移动到
(
x
+
1
,
y
+
1
)
(x+1,y+1)
(x+1,y+1)
若存在
(
x
,
y
′
<
y
)
(x,y'<y)
(x,y′<y) 为关键点,那么移动到
(
x
+
1
,
y
)
(x+1,y)
(x+1,y)
若存在
(
x
′
<
x
,
y
)
(x'<x,y)
(x′<x,y) 为关键点,那么移动到
(
x
,
y
+
1
)
(x,y+1)
(x,y+1)
否则当前
f
x
,
y
f_{x,y}
fx,y 为
1
1
1,此时只需要移动到
(
x
+
1
,
y
+
1
)
(x+1,y+1)
(x+1,y+1) 就可以了
我们按
x
x
x 做扫描线,维护
(
x
′
<
x
,
y
)
(x'<x,y)
(x′<x,y) 的
y
y
y 的集合,复杂度
O
(
n
log
n
)
\mathcal{O}(n\log n)
O(nlogn)
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define fi first
#define se second
using namespace std;
cs int oo = 1e9 + 7;
typedef pair<int, int> pi;
cs int N = 1e5 + 50;
int n, m, ans[N], y[N];
map<pi, bool> ex;
map<int, vector<int> > G;
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> n >> m;
for(int i = 1, x, y; i <= n; i++){
scanf("%d%d", &x, &y);
ex[pi(x, y)] = true, G[x].pb(y);
} ex[pi(0, 0)] = 1, G[0].pb(0);
for(int i = 1, x, y; i <= m; i++){
scanf("%d%d", &x, &y);
if(!ex[pi(x, y)]) G[x].pb(-i), ::y[i] = y;
}
int lp = -1, lm = 0; set<int> Y;
for(auto z : G){
int x = z.fi; vector<int> e = z.se;
for(int i = lp + 1; i < x; ){
while(Y.find(lm) != Y.end()) ++lm;
auto t = Y.lower_bound(lm);
if(t == Y.end()) { lm += x - i; break; }
int dt = min(*t - lm, x - i); lm += dt, i += dt;
} while(Y.find(lm) != Y.end()) ++lm; int mn = oo;
for(int z : G[x]) if(z >= 0) mn = min(mn, z);
if(lm < mn) Y.insert(lm), mn = lm;
for(int z : G[x]) {
if(z >= 0) Y.insert(z);
else ans[-z] = y[-z] != mn;
} lp = x;
} for(int i = 1; i <= m; i++)
cout << (ans[i] ? "WIN" : "LOSE") << '\n';
return 0;
}
F
分治,考虑求出
∑
i
∈
[
l
,
m
i
d
]
∑
r
∈
[
m
i
d
+
1
,
r
]
d
i
a
m
(
i
,
j
)
\sum_{i\in[l,mid]}\sum_{r\in[mid+1,r]}diam(i,j)
∑i∈[l,mid]∑r∈[mid+1,r]diam(i,j)
我们对左边的每个后缀
i
i
i 求出
(
u
,
R
)
(u,R)
(u,R)
表示用
(
u
,
R
)
(u,R)
(u,R) 可以包住集合
[
i
,
m
i
d
]
[i,mid]
[i,mid] 其中
R
R
R 是极小的
合并两个集合可以通过树上倍增实现
枚举左边的一个
i
i
i,那么
j
j
j 可以分成三类,
即
[
m
i
d
+
1
,
j
]
∈
[
i
,
m
i
d
]
,
[
i
,
m
i
d
]
∈
[
m
i
d
+
1
,
j
]
,
o
t
h
e
r
w
i
s
e
[mid+1,j]\in[i,mid],[i,mid]\in [mid+1,j],otherwise
[mid+1,j]∈[i,mid],[i,mid]∈[mid+1,j],otherwise
可以通过双指针来维护
对于前两类的贡献可以快速算,中间的贡献相当于是
∑
j
r
i
+
r
j
+
d
(
u
i
,
u
j
)
\sum_jr_i+r_j+d(u_i,u_j)
∑jri+rj+d(ui,uj)
用点分树维护就可以了
#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
typedef long long ll;
cs int N = 2e5 + 50;
int n; vector<int> G[N];
void add(int u, int v){ G[u].pb(v), G[v].pb(u); }
int sz[N], Mx, rt, all; bool ban[N];
void gsz(int u, int f){
sz[u] = 1; for(int v : G[u])
if(!ban[v] && v != f)
gsz(v, u), sz[u] += sz[v];
} void grt(int u, int f){
int mx = all - sz[u];
for(int v : G[u]) if(v != f && !ban[v])
grt(v, u), mx = max(mx, sz[v]);
if(mx < Mx) Mx = mx, rt = u;
} int anc[N], _d[N], d[20][N];
void dfs(int u, int f, int r){
for(int v : G[u])
if(v != f && !ban[v])
d[r][v] = d[r][u] + 1, dfs(v, u, r);
} void work(int u, int f){
gsz(u, 0); Mx = all = sz[u]; grt(u, 0);
ban[u = rt] = true;
_d[u] = _d[anc[u] = f] + 1;
dfs(u, 0, _d[u]);
for(int v : G[u]) if(!ban[v]) work(v, u);
}
int c[N]; ll b[N], _b[N];
void ins(int x, int vl){
for(int u = x, t = _d[x]; u; u = anc[u], --t){
if(t > 1) _b[u] += vl * d[t - 1][x];
c[u] += vl, b[u] += vl * d[t][x];
}
} ll ask(int x){
ll ans = b[x];
for(int u = x, v = anc[x], t =
_d[x] - 1; v; u = v, v = anc[v], --t)
ans += 1ll * (c[v] - c[u]) * d[t][x] + b[v] - _b[u];
return ans;
}
int dep[N], fa[N][20];
void pre_dfs(int u, int f){
dep[u] = dep[fa[u][0] = f] + 1;
for(int i = 1; i <= 17; i++)
fa[u][i] = fa[fa[u][i - 1]][i - 1];
for(int v : G[u]) if(v != f) pre_dfs(v, u);
} int LCA(int x, int y){
if(dep[x] < dep[y]) swap(x, y);
for(int i = 17; ~i; i--)
if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
if(x == y) return x;
for(int i = 17; ~i; i--)
if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
} int dist(int x, int y){ return dep[x] + dep[y] - 2 * dep[LCA(x, y)]; }
int jmp(int x, int d){
for(int i = 17; ~i; i--)
if(d >= (1 << i)) d -= 1 << i, x = fa[x][i]; return x;
} int fnd(int x, int y, int d){
int l = LCA(x, y);
if(dep[x] - dep[l] >= d) return jmp(x, d);
d -= dep[x] - dep[l];
return jmp(y, dep[y] - dep[l] - d);
}
struct lll{
int u, r;
lll operator + (cs lll &z) {
int d = dist(u, z.u);
if(r + d <= z.r) return z;
if(z.r + d <= r) return *this;
int t = (r + z.r + d) / 2;
int p = fnd(u, z.u, t - r);
return (lll){p, t};
} bool in(cs lll &z){ return z.r + dist(u, z.u) <= r; }
bool _in(cs lll &z){ return z.r + dist(u, z.u) < r; }
} p[N]; ll Ans;
void cope(int l, int r){
if(l == r) return;
int mid = (l + r) >> 1;
p[mid] = (lll){mid, 0};
p[mid + 1] = (lll){mid + 1, 0};
for(int i = mid - 1; i >= l; i--)
p[i] = (lll){i, 0} + p[i + 1];
for(int i = mid + 2; i <= r; i++)
p[i] = (lll){i, 0} + p[i - 1];
int lp = mid, rp = mid + 1;
static ll s[N]; s[r + 1] = 0;
for(int i = r; i > mid; i--)
s[i] = s[i + 1] + p[i].r;
for(int i = mid; i >= l; i--){
while(rp <= r && !p[rp].in(p[i])) ins(p[rp].u, 1), ++rp;
while(lp < r && p[i]._in(p[lp + 1])) ++lp, ins(p[lp].u, -1);
Ans += s[rp] + 1ll * p[i].r * (lp - mid);
Ans += (s[lp + 1] - s[rp] + 1ll *
p[i].r * (rp - lp - 1) + ask(p[i].u)) / 2;
} while(lp + 1 < rp) ++lp, ins(p[lp].u, -1);
cope(l, mid), cope(mid + 1, r);
}
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> n;
for(int i = 1, u, v; i < n; i++)
scanf("%d%d", &u, &v),
add(u, i + n), add(i + n, v);
pre_dfs(1, 0); work(1, 0);
cope(1, n);
cout << Ans << '\n';
}