2025-2 好题
- 2025-2 好题
- UOJ Round 29 B - 数字生命
- P10063 [SNOI2024] 平方数
- AGC070C - No Streak
- AGC070B - Odd Namori
- リテラチュア
- ブルーアーカイブ
UOJ Round 29 B - 数字生命
首先想到差分,差分后是正的就看成一些起点,负的就看成是一些终点
然后题目就相当于要对每一对起点和终点配对,然后塞一些区间覆盖进去
考虑集合幂级数,设 \(F_{i,j}\) 位第 \(i\) 个起点到第 \(j\) 个终点的可行集合,并附上随机权值,乘法是子集卷积
那么答案集合即为:
和积式不好算,不难发现乘个额外因子是没有关系的,所以考虑计算行列式:
但是子集卷积有点难算,但是可以改成或卷积,这样如果有元素或了起来,这样 \(\sum \mathrm{len}\) 就会变小,判一下即可
用 FWT 算出每个集合幂级数的点值,然后计算行列式,最后做一遍 IFWT 得到答案即可。
时间复杂度 \(O(2^m m^3)\)。
ケロシの代码
const int N = 1e5 + 5;
const int M = 17;
const int P = 998244353;
inline int add(int x, int y) { return (x + y < P ? x + y : x + y - P); }
inline void Add(int & x, int y) { x = (x + y < P ? x + y : x + y - P); }
inline int sub(int x, int y) { return (x < y ? x - y + P : x - y); }
inline void Sub(int & x, int y) { x = (x < y ? x - y + P : x - y); }
inline int mul(int x, int y) { return (1ll * x * y) % P; }
inline void Mul(int & x, int y) { x = (1ll * x * y) % P; }
int fp(int x, int y) {int res = 1;for(; y; y >>= 1) {if(y & 1) Mul(res, x);Mul(x, x);}return res;
}
mt19937 rnd(time(0));
int n, m;
int a[N], b[N], c[N];
int st[N], ed[N], tot;
int s[1 << M];
int A[1 << M][M][M], F[1 << M];
void ADD(int x[M][M], int y[M][M]) {REP(i, tot) REP(j, tot)Add(x[i][j], y[i][j]);
}
void OR(int lim) {for(int i = 1; i < lim; i <<= 1) for(int j = 0; j < lim; j += (i << 1))REP(k, i)ADD(A[j + k + i], A[j + k]);
}
void IOR(int lim) {for(int i = 1; i < lim; i <<= 1) for(int j = 0; j < lim; j += (i << 1))REP(k, i)Sub(F[j + k + i], F[j + k]);
}
int det(int a[M][M], int n) {int res = 1, w = 1;REP(i, n) {if(! a[i][i]) {FOR(j, i + 1, n - 1) if(a[j][i]) {swap(a[i], a[j]);res = sub(0, res);break;}}if(! a[i][i]) return 0;Mul(res, a[i][i]);FOR(j, i + 1, n - 1) {Mul(w, a[i][i]);int val = a[j][i];FOR(k, i, n - 1)a[j][k] = sub(mul(a[i][i], a[j][k]), mul(a[i][k], val));}}return mul(res, fp(w, P - 2));
}
void solve() {cin >> n >> m;FOR(i, 1, n) cin >> a[i];int sum = 0;FOR(i, 1, n) sum += a[i];ROF(i, n + 1, 1) a[i] -= a[i - 1];FOR(i, 1, n + 1) while(a[i] > 0) a[i] --, st[tot ++] = i;tot = 0;FOR(i, 1, n + 1) while(a[i] < 0) a[i] ++, ed[tot ++] = i;if(tot > m) {REP(_, 1 << m) cout << 0;cout << endl;return;}REP(i, m) cin >> b[i];REP(S, 1 << m) {REP(i, m) if(S >> i & 1) s[S] += b[i];REP(i, tot) REP(j, tot) if(ed[j] - st[i] == s[S])A[S][i][j] = rnd() % P;}OR(1 << m);REP(S, 1 << m) F[S] = det(A[S], tot);IOR(1 << m);REP(S, 1 << m) cout << (sum == s[S] && F[S]);cout << endl;
}
P10063 [SNOI2024] 平方数
这题值域太大,都不能分解质因数
考虑一个平方数模一个随机大质数大概率是这个大质数的二次剩余
而在模一个大质数下,有一半的数有二次剩余,可以看作 \(\frac{1}{2}\) 的概率有二次剩余
所以随机 \(T=40\) 个大质数来判断,这样错误概率只有 \(\frac{1}{2^{40}}\)。
接下来考虑怎么判区间是否是二次剩余,注意到判断二次剩余的方法是计算 \(a^\frac{P+1}{2} \bmod P\) 是 \(1\) 还是 \(-1\)
所以可以对于每个 \(a_i\) 单独计算 \({a_i}^\frac{P+1}{2} \bmod P\),然后区间只要有偶数个 \(-1\) 就是合法的,可以用 map 快速计算合法区间数量。
时间复杂度 \(O(T n \log n)\)。
ケロシの代码
const int N = 3e5 + 5;
const int V = 1e5;
const int M = 40;
int n;
int128 a[N], s[M];
ll f[N], b[N]; int len;
vector<int> e[N];
ll pri[M];
ll p[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
mt19937 rnd(time(0));
ll rd() {return 1ll * (rnd() >> 3) * rnd() + rnd();
}
ll mul(ll x, ll y, ll p) {ll k = (1.l * x * y) / (1.l * p);ll res = x * y - k * p;res -= p;while(res < 0) res += p;return res;
}
ll fp(ll x, ll y, ll p) {ll res = 1;for(; y; y >>= 1) {if(y & 1) res = mul(res, x, p);x = mul(x, x, p);}return res;
}
bool Miller_Rabin(ll n, ll a) {int r = 0; ll b = n - 1;while(! (b & 1)) b >>= 1, r ++;ll val = fp(a, b, n);if(val == 1) return 1;REP(i, r) {if(val == n - 1) return 1;val = mul(val, val, n);}return 0;
}
bool ip(ll n) {if(n < 2) return 0;REP(i, 7) {if(n == p[i]) return 1;if(p[i] % n == 0) continue;if(n % p[i] == 0) return 0;if(! Miller_Rabin(n, p[i])) return 0;}return 1;
}
int128 read() {int128 res = 0;char c = getchar();while(c < '0' || c > '9') c = getchar();while('0' <= c && c <= '9') res = res * 10 + c - '0', c = getchar();return res;
}
void init() {REP(i, M) {ll x = rd();while(! ip(x)) x = rd();pri[i] = x;}
}
void solve() {n = read();FOR(i, 1, n) a[i] = read();init();REP(i, M) s[i] = 1;ROF(i, n, 1) {REP(j, M) s[j] = mul(s[j], a[i] % pri[j], pri[j]);REP(j, M) {ll val = fp(s[j] % pri[j], (pri[j] - 1) >> 1, pri[j]);if(val != 1) f[i] |= 1ll << j;}}FOR(i, 1, n + 1) b[++ len] = f[i];sort(b + 1, b + len + 1);len = unique(b + 1, b + len + 1) - b - 1;FOR(i, 1, n + 1) f[i] = lower_bound(b + 1, b + len + 1, f[i]) - b;ll ans = 0;vector<PII> Ans;ROF(i, n + 1, 1) {ans += SZ(e[f[i]]);e[f[i]].push_back(i);}FOR(i, 1, n) reverse(ALL(e[i]));FOR(i, 1, n) {for(int r : e[f[i]]) if(r > i) {Ans.push_back({i, r - 1});if(SZ(Ans) == V) break;}if(SZ(Ans) == V) break;}cout << ans << endl;for(auto h : Ans) cout << FI(h) << " " << SE(h) << endl;
}
AGC070C - No Streak
对于 Alice 的赢的次数总是要大于 Bob 的限制,不难想到反射容斥
但是不能连胜的条件相当于对折线的形态有限制,翻折后形态就会改变
时间复杂度 \(O(n)\)。
ケロシの代码
const int N = 3e7 + 5;
const int P = 1e9 + 7;
inline int add(int x, int y) { return (x + y < P ? x + y : x + y - P); }
inline void Add(int & x, int y) { x = (x + y < P ? x + y : x + y - P); }
inline int sub(int x, int y) { return (x < y ? x - y + P : x - y); }
inline void Sub(int & x, int y) { x = (x < y ? x - y + P : x - y); }
inline int mul(int x, int y) { return (1ll * x * y) % P; }
inline void Mul(int & x, int y) { x = (1ll * x * y) % P; }
inline int mul(initializer_list<int> a) {int res = 1;for(int x : a) Mul(res, x);return res;
}
int fp(int x, int y) {int res = 1;for(; y; y >>= 1) {if(y & 1) Mul(res, x);Mul(x, x);}return res;
}
int n, A, B, E;
int fac[N], finv[N];
void init(int n) {fac[0] = 1;FOR(i, 1, n) fac[i] = mul(fac[i - 1], i);finv[n] = fp(fac[n], P - 2);ROF(i, n - 1, 0) finv[i] = mul(finv[i + 1], i + 1);
}
int C(int x, int y) {if(x < y || y < 0) return 0;return mul(mul(fac[x], finv[y]), finv[x - y]);
}
int F(int A, int B, int E) {if(! B) return C(E + 1, A);int res = 0;FOR(i, 1, B) {Add(res, mul({C(B - 1, i - 1), C(A - 1, i - 2), C(E + i * 2 - 1, A + B)}));Add(res, mul({2, C(B - 1, i - 1), C(A - 1, i - 1), C(E + i * 2, A + B)}));Add(res, mul({C(B - 1, i - 1), C(A - 1, i), C(E + i * 2 + 1, A + B)}));}return res;
}
void solve() {cin >> n >> A >> B; E = n - A - B;init(N - 1);int ans = F(A, B, E);Sub(ans, F(A, B - 1, E));Sub(ans, F(A + 1, B - 1, E - 1));Sub(ans, F(A, B - 1, E - 1));cout << ans << endl;
}
AGC070B - Odd Namori
ケロシの代码
const int N = 1e5 + 5;
const int P = 998244353;
inline int add(int x, int y) { return (x + y < P ? x + y : x + y - P); }
inline void Add(int & x, int y) { x = (x + y < P ? x + y : x + y - P); }
inline int mul(int x, int y) { return (1ll * x * y) % P; }
inline void Mul(int & x, int y) { x = (1ll * x * y) % P; }
int fp(int x, int y) {int res = 1;for(; y; y >>= 1) {if(y & 1) Mul(res, x);Mul(x, x);}return res;
}
int n, p[N], d[N], s[N];
void solve() {cin >> n;FOR(i, 2, n) cin >> p[i];d[1] = 1;FOR(i, 2, n) d[i] = d[p[i]] + 1;int ans = mul(n, fp(n - 1, n - 1));FOR(i, 1, n) Add(ans, fp(n - 1, n - d[i]));FOR(i, 2, n) s[d[i] - 1] ++;ROF(i, n, 1) s[i] += s[i + 1];FOR(i, 1, n - 1) Add(ans, mul(mul(n, s[i]), fp(n - 1, n - i - 1)));cout << ans << endl;
}
リテラチュア
リテラチュア - 上田麗奈 (うえだ れいな)
词:RIRIKO
曲:RIRIKO
编曲:伊藤賢
彩られていけば幻想が
カタチあるものになるように
描いてゆける 叶えてゆけるんだ
優しく吹いた風が
古いページ捲るように
振り返るけど
「ううん いいのよ」
知らないことだらけの
出会い別れの話
滲むインクをそっとなぞった
どこ行くの?
少し遠くまで
置いてきたものは夢に
好きだから選ぶ
選びながら私になってゆく
「また会いましょう
約束だから」
あなたはそう微笑んだ
「また会いましょう」
小指のまじない
誰かの声がして目が覚めた
期待されていること
見向きさえされないこと
どちらが良いの?
「ううん どちらも」
嬉しいし不安だし
私だって必死だし
主人公になれていますか?
雨が降る 一つ 一つずつ
誰もいない世界みたい
満月も見ないフリしながら
明日を待っている
「信じるだけで叶えられるわ」
一人はそう 背を押した
「信じるだけで助けられるわ」
一人はそう まるで願うように
やがて青い空の上で
星は笑う
本で見たような夜だった
雨は止み 頬をつたう
朝が来た 忘れないでいてね
旅のリテラチュア
どこ行くの?
少し遠くまで
置いてきたものは夢に
好きだから選ぶ
選びながら私になってゆく
「また会いましょう
約束だから」
あなたはそう微笑んだ
「また会いましょう」
小指のまじない
誰かを信じても良いのかな