正睿 25 年省选联考 Day 7
正睿 25 年省选联考 Day 7
得分
| T1 | T2 | T3 | 总分 | 排名 |
|---|---|---|---|---|
| \(100\) | \(0\) | \(0\) | \(100\) | \(15/47\) |
题解
T1 城市地平线
简单题。考虑从小到大删数,每一次删完后跨过当前数字的所有区间都是新的答案。假设当前位置左边有 \(a\) 个数,右边有 \(b\) 个数,那么长度为 \(i\) 的区间的方案数为 \(\min(i-1,b)-\max(1,i-a)+1\),拆开后分类讨论一下,可以简单用树状数组维护出每种区间的数量。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int Maxn = 2e5 + 5;
const int Inf = 2e9;
int n, L, R;
int a[Maxn], pos[Maxn];
struct BIT {
int c[Maxn];
int lowbit(int x) {return x & (-x);}
void mdf(int x, int val) {for(int i = x; i <= n; i += lowbit(i)) c[i] += val;}
int query(int x) {int sum = 0;for(int i = x; i; i -= lowbit(i)) sum += c[i]; return sum;}
void mdf(int l, int r, int val) {mdf(l, val), mdf(r + 1, -val);}
}B1, B2, B3;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> L >> R;
for(int i = 1; i <= n; i++) {
cin >> a[i];
pos[a[i]] = i;
B1.mdf(i, 1);
}
for(int i = 1; i <= n; i++) {
B3.mdf(i, i, n - i + 1);
}
for(int i = 1; i <= n; i++) {
int p = pos[i];
if(!p) continue;
B1.mdf(p, -1);
int a = B1.query(p - 1), b = B1.query(n) - B1.query(p), s = min(a, b);
if(!s) continue;
B3.mdf(2, a + b, a);
if(2 <= b + 1) B2.mdf(2, b + 1, 1);
if(b + 2 <= a + b) B3.mdf(b + 2, a + b, b + 1);
if(2 <= a + 1) B3.mdf(2, a + 1, -(a + 1));
if(a + 2 <= a + b) B2.mdf(a + 2, a + b, -1);
}
int ans = 0;
for(int i = L; i <= R; i++) {
int res = B2.query(i) * i + B3.query(i);
ans ^= res;
}
cout << ans << '\n';
return 0;
}
T2 合成史莱姆
首先考虑普通情况,容易发现史莱姆合并的过程对最终答案没有影响,只需要考虑每个史莱姆移到每一个餐盘的概率即可。考虑设 \(f(i,j)\) 表示所有史莱姆经过格子 \((i,j)\) 的总次数的期望,然后从这个格子走出棋盘的概率就是 \(\tfrac 14 f(i,j)\)。我们有如下转移:
\[f(i,j)=\dfrac{1}{4}\sum f(x,y)+a(i,j)
\]
其中 \((x,y)\) 与 \((i,j)\) 相邻,\(a(i,j)\) 表示该位置初始有无史莱姆。显然我们可以高斯消元 \(O(n^3)\) 求出答案。
考虑优化,在矩形上进行高斯消元有一个经典套路,我们设第一行为主元,以此表示后面的位置,用最后一行列方程,这样变量数就是 \(O(\sqrt n)\) 的,复杂度 \(O(n\sqrt n)\)。
考虑在棋盘上进行这个过程,我们可以找一个格子为起点,然后进行广搜,如果当前格子无法用相邻格子表示则新设一个主元,否则用当前设的未知数表示。并且每次我们得出一个点的表达式后要再深搜一次,在不设新未知数的情况下尽可能多得出一些格子的表达式。可以证明这样的复杂度是正确的。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int Maxn = 2e5 + 5;
const int Inf = 2e9;
const int Mod = 998244353;
const int Inv4 = 748683265;
int add(int x, int y) {return x + y >= Mod ? x + y - Mod : x + y;}
int del(int x, int y) {return x - y < 0 ? x - y + Mod : x - y;}
int n;
struct node {
int x, y, t;
}a[Maxn];
int mn[Maxn], mx[Maxn];
vector <int> v[Maxn];
#define pii pair<int, int>
#define mk make_pair
map <pii, int> mp, ans;
vector <int> tar;
int qpow(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res = res * a % Mod;
a = a * a % Mod; b >>= 1;
}
return res;
}
int tot = 0;
int val[805];
int nx[] = {1, -1, 0, 0};
int ny[] = {0, 0, 1, -1};
struct Coef{
int a[805];
int& operator[](int x) {return a[x];}
Coef operator + (Coef b) {
Coef c;
for(int i = 0; i <= tot; i++) c[i] = add(a[i], b[i]);
return c;
}
Coef operator - (Coef b) {
Coef c;
for(int i = 0; i <= tot; i++) c[i] = del(a[i], b[i]);
return c;
}
Coef operator - (int b) {
Coef c = *this; c[0] = del(c[0], b);
return c;
}
Coef operator + (int b) {
Coef c = *this; c[0] = add(c[0], b);
return c;
}
Coef operator * (int b) {
Coef c;
for(int i = 0; i <= tot; i++) c[i] = a[i] * b % Mod;
return c;
}
int calc() {
int res = a[0];
for(int i = 1; i <= tot; i++) res = add(res, a[i] * val[i] % Mod);
return res;
}
}mat[40005], eq[805];
queue <int> q;
bool vis[Maxn], limed[Maxn];
void dfs(int x) {
int dx = a[x].x, dy = a[x].y;
int t1 = mp[mk(dx, dy - 1)], t2 = mp[mk(dx - 1, dy)], t3 = mp[mk(dx, dy + 1)], t4 = mp[mk(dx + 1, dy)];
int num = vis[t1] + vis[t3] + vis[t2] + vis[t4], cnt = (t1 != 0) + (t2 != 0) + (t3 != 0) + (t4 != 0);
if(num == cnt - 1) {
limed[x] = 1;
Coef F = (mat[x] - a[x].t) * 4 - mat[t1] - mat[t2] - mat[t3] - mat[t4];
if(t1 && !vis[t1]) mat[t1] = F, vis[t1] = 1, dfs(t1), q.push(t1);
if(t2 && !vis[t2]) mat[t2] = F, vis[t2] = 1, dfs(t2), q.push(t2);
if(t3 && !vis[t3]) mat[t3] = F, vis[t3] = 1, dfs(t3), q.push(t3);
if(t4 && !vis[t4]) mat[t4] = F, vis[t4] = 1, dfs(t4), q.push(t4);
}
}
void bfs(int S) {
q.push(S);
mat[S][++tot] = 1;
vis[S] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
int x = a[u].x, y = a[u].y;
if(limed[u]) continue;
int num = 0, pos[4] = {u, 0, 0, 0}, cnt = 0;
for(int i = 0; i < 4; i++) {
int rx = x + nx[i], ry = y + ny[i], id = mp[mk(rx, ry)];
if(!id) continue; cnt++;
if(vis[id]) pos[++num] = id;
}
for(int i = 0; i < 4; i++) {
int rx = x + nx[i], ry = y + ny[i], id = mp[mk(rx, ry)];
if(!id || vis[id]) continue;
limed[u] = 1;
if(num != cnt - 1) {
mat[id][++tot] = 1;
pos[++num] = id;
}
else {
mat[id] = (mat[pos[0]] - a[pos[0]].t) * 4 - mat[pos[1]] - mat[pos[2]] - mat[pos[3]];
}
q.push(id); vis[id] = 1;
dfs(id);
}
}
}
void gauss(int m) {
for(int i = 1; i <= m; i++) eq[i][0] = (Mod - eq[i][0]) % Mod;
for(int i = 1; i <= m; i++) {
int u = i;
for(int j = 1; j <= m; j++) {
if(eq[j][j] && j < i) continue;
if(eq[j][i] > eq[u][i]) u = j;
}
swap(eq[u], eq[i]);
for(int j = 1; j <= m; j++) {
if(i != j) {
int p = eq[j][i] * qpow(eq[i][i], Mod - 2) % Mod;
eq[j] = eq[j] - eq[i] * p;
}
}
}
for(int i = 1; i <= m; i++) {
val[i] = eq[i][0] * qpow(eq[i][i], Mod - 2) % Mod;
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
mt19937 rnd(time(0));
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i].x >> a[i].y >> a[i].t;
mp[mk(a[i].x, a[i].y)] = i;
}
int start = 1;
bfs(start);
int m = 0;
for(int i = 1; i <= n; i++) {
if(limed[i]) continue;
int dx = a[i].x, dy = a[i].y;
int t1 = mp[mk(dx, dy - 1)], t2 = mp[mk(dx - 1, dy)], t3 = mp[mk(dx, dy + 1)], t4 = mp[mk(dx + 1, dy)];
eq[++m] = (mat[t1] + mat[t2] + mat[t3] + mat[t4]) * Inv4 + a[i].t - mat[i];
}
gauss(tot);
for(int i = 1; i <= n; i++) {
int num = mat[i].calc() * Inv4 % Mod;
for(int j = 0; j < 4; j++) {
int px = a[i].x + nx[j], py = a[i].y + ny[j];
if(!mp[mk(px, py)]) (ans[mk(px, py)] += num) %= Mod;
}
}
int res = 0;
for(auto i : ans) res ^= i.second;
cout << res << '\n';
return 0;
}
T3 维修喷水管
出题人自己发明的科技,改不了一点。

浙公网安备 33010602011771号