2026-01-03 水水的省选模拟赛 Day 1 hetao1733837 的刷题记录
赛时
click
赛事思路
卧槽......
两个方向,一个是从如何求 gcd \gcd gcd 来思考......
另一个是从两边同时乘 gcd \gcd gcd 来思考......这个好像是有部分分的。
行,把题目通读了......
08点43分
开始拼包吧......
从第二个特殊性质出发,似乎这个平方很有意味啊......
我先拼完这个......
那你相等不也是 1 1 1 次方吗?
有意思......
09点07分
我并非很会......
显然, x p x^p xp 和 x p \sqrt[p]{x} px 是有的,但是这个 x p \sqrt[p]{x} px 能不能取到要看具体数据。
09点10分
或者再换个思路,使得 gcd ( x , y ) p + 1 = x y \gcd(x,y)^{p+1}=xy gcd(x,y)p+1=xy,然后考虑这个 gcd \gcd gcd 怎么得到的......
显然是
gcd ( x , y ) p + 1 = gcd ( y , x % y ) p + 1 = ... \gcd(x,y)^{p+1}=\gcd(y,x\%y)^{p+1}=\dots gcd(x,y)p+1=gcd(y,x%y)p+1=...
那有啥用呢?
进行分解质因数......
取 gcd \gcd gcd 相当于取质因数的交集......取 p + 1 p+1 p+1 次方相当于把交际每个数的个数都乘上 p + 1 p+1 p+1。
那么,等式右侧一定只会出现 x x x 质因数的子集,也就是说,那 x = 576 = 2 6 × 3 2 x=576=2^6\times 3^2 x=576=26×32 举例, y y y 也必须由 2 n × 3 m 2^n\times3^m 2n×3m 的形式。
则 ( 2 min ( 6 , n ) × 3 m i n ( 2 , m ) ) 4 = 2 6 + n × 3 2 + m {(2^{\min(6,n)}\times 3^{min(2,m)})}^4=2^{6+n}\times3^{2+m} (2min(6,n)×3min(2,m))4=26+n×32+m。
即
{ min ( 6 , n ) 4 = 6 + n min ( 2 , m ) 4 = 2 + m \begin{cases} {\min(6,n)}^4=6+n\\ {\min(2,m)}^4=2+m \end{cases} {min(6,n)4=6+nmin(2,m)4=2+m
答案数即为方程解的个数。
mhh 也不会......那还玩个 damn?
形式化的, x = x 1 f 1 × x 2 f 2 × ⋯ × x n f n x=x_1^{f_1}\times x_2^{f_2}\times\dots\times x_n^{f_n} x=x1f1×x2f2×⋯×xnfn, y = x 1 g 1 × x 2 g 2 × ⋯ × x n g n y=x_1^{g_1}\times x_2^{g_2}\times\dots\times x_n^{g_n} y=x1g1×x2g2×⋯×xngn,
求
{ min ( f 1 , g 1 ) p + 1 = f 1 + g 1 min ( f 2 , g 2 ) p + 1 = f 2 + g 2 ⋮ min ( f n , g n ) p + 1 = f n + g n \begin{cases} {\min(f1,g1)}^{p+1}=f1+g1\\ {\min(f2,g2)}^{p+1}=f2+g2\\ \vdots\\ {\min(f_n,g_n)}^{p+1}=f_n+g_n\\ \end{cases} ⎩ ⎨ ⎧min(f1,g1)p+1=f1+g1min(f2,g2)p+1=f2+g2⋮min(fn,gn)p+1=fn+gn
解的个数。
09点38分
还是不会......
11点10分
成功盒出 T 1 T1 T1,但我并不很想抄......
ddlc
赛时思路
盒原
bur,水印都不去?
想到一个......呃......建图之类的吧......就是只能管到自己开始到这一列的结尾......
行,吧题目通读了......
09点45分
依我之见,只要每一列都有陆地最终一定不无解!
那么,如何判断联通?注意一下子任务......
10点19分
写出来 WA 了......并非很想调吧......
10点31分
没过大样例......
不想写了......
math
赛时思路
有点像扩展欧几里得的形式......但又不完全一样......
等一下...... n ≤ 25 n\le 25 n≤25......有搞头......
bur,先开 T3 有点恐怖了吧......感觉我会 40pts......
那,先打一个 40 的?
呃......我承认,我 40pts 也不会......
10点43分
那我先拼 10pts 呗......应该有了......
10点47分
我想想一般咋去 ⌊ ⌋ \left\lfloor\,\right\rfloor ⌊⌋ 的......要不,先考虑没有 ⌊ ⌋ \left\lfloor\,\right\rfloor ⌊⌋ 会发生什么......
得到
1 x 1 + 1 x 2 + ⋯ + 1 x n = x y \frac{1}{x_1}+\frac{1}{x_2}+\dots+\frac{1}{x_n}=\frac{x}{y} x11+x21+⋯+xn1=yx
这能干啥?
不打了/ll
11点27分
成功盒出原,但我不想抄。发现花花自己出的题在洛谷上没交过......
赛后
没有交,初始骗的应该有 20 左右吧......
据说,今天是黄绿蓝,T1 是不是黄不知道,反正 T2,T3 是绿蓝......
合着机房大多数人稳切黄都没有?就稳切个橙?
T2,T3给出来原了,先补了......
ZYZ P7843 click
ZYZ提交链接:"别点!!!"(click)
居然是 zjx 自己出的吗!这么牛!
分析
T1......
zjx 题解写的啥啊/ll
哦,写的相当不错。
操了,就差亿点吧......
赛时错了一个错误的决定,就是两边同乘 gcd \gcd gcd。那么,我们再次思考,若 x = x 1 f 1 × x 2 f 2 × ⋯ × x n f n x=x_1^{f_1}\times x_2^{f_2}\times\dots\times x_n^{f_n} x=x1f1×x2f2×⋯×xnfn, y = x 1 g 1 × x 2 g 2 × ⋯ × x n g n y=x_1^{g_1}\times x_2^{g_2}\times\dots\times x_n^{g_n} y=x1g1×x2g2×⋯×xngn,则
gcd ( x , y ) = x 1 min ( f 1 , g 1 ) × x 2 min ( f 2 , g 2 ) × ⋯ × x n min ( f n , g n ) lcm ( x , y ) = x 1 max ( f 1 , g 1 ) × x 2 max ( f 2 , g 2 ) × ⋯ × x n max ( f n , g n ) \gcd(x,y)=x_1^{\min(f_1,g_1)}\times x_2^{\min(f_2,g_2)}\times\dots\times x_n^{\min(f_n,g_n)} \\ \operatorname{lcm}(x,y)=x_1^{\max(f_1,g_1)}\times x_2^{\max(f_2,g_2)}\times\dots\times x_n^{\max(f_n,g_n)} gcd(x,y)=x1min(f1,g1)×x2min(f2,g2)×⋯×xnmin(fn,gn)lcm(x,y)=x1max(f1,g1)×x2max(f2,g2)×⋯×xnmax(fn,gn)
唐在这了。
那么有
{ p × min ( f 1 , g 1 ) = max ( f 1 , g 1 ) p × min ( f 2 , g 2 ) = max ( f 2 , g 2 ) ⋮ p × min ( f n , g n ) = max ( f n , g n ) \begin{cases} p\times\min(f_1,g_1)=\max(f_1,g_1)\\ p\times\min(f_2,g_2)=\max(f_2,g_2)\\ \vdots\\ p\times\min(f_n,g_n)=\max(f_n,g_n)\\ \end{cases} ⎩ ⎨ ⎧p×min(f1,g1)=max(f1,g1)p×min(f2,g2)=max(f2,g2)⋮p×min(fn,gn)=max(fn,gn)
上面同样推出了 x , y x,y x,y 质因数集相同的结论,故对 x x x 进行质因数分解,然后得出 f f f 数组,解一下就行。
所以,差的只是一步 lcm \operatorname{lcm} lcm 的转化......以及最后分讨。
活该你写不出来! ( x a ) b (x^a)^b (xa)b 等于 x a b x^{ab} xab,自己看看上午推成啥了?
ZYZOJ AC 代码
cpp
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
int T;
int x, p;
signed main(){
freopen("click.in", "r", stdin);
freopen("click.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> T;
while (T--){
cin >> x >> p;
if (p == 1){
cout << 1 << '\n';
continue;
}
map<int, int> buc;
int xx = x;
for (int i = 2; i <= sqrt(x); i++){
while (xx % i == 0){
xx /= i;
buc[i]++;
}
}
int ans = 1;
for (auto tmp : buc){
int f = tmp.second;
if (f % p == 0)
ans = (ans * 2) % mod;
}
cout << ans << '\n';
}
}
LG13736 [JOIGST 2025] 日本浮现 / Japan Emerges
原题链接:[JOIGST 2025] 日本浮现 / Japan Emerges
ZYZ提交链接:Doki Doki Forever!(ddlc)
分析
这道是 T2......
真是原啊?水印都不去/ll
应该按照建图的思路走下去的......
那么,对于一块陆地 ( x , y ) (x,y) (x,y):
当另一块陆地位于 ( x ′ , y ) (x',y) (x′,y),其中 x ′ > x x'>x x′>x,经过 ( x ′ − x − 1 ) (x'-x-1) (x′−x−1) 天,二者联通;
当另一块陆地位于 ( x ′ , y − 1 ) (x',y-1) (x′,y−1),其中 x ′ > x x'>x x′>x,经过 ( x ′ − x ) (x'-x) (x′−x) 天,二者联通;
当另一块陆地位于 ( x ′ , y + 1 ) (x',y + 1) (x′,y+1),其中 x ′ > x x'>x x′>x,经过 ( x ′ − x ) (x'-x) (x′−x) 天,二者联通。
建图,显然建图复杂度不会很劣,因为只考虑了三列,点的总数可以接受。
那么,要求每个点统计联通时取最大值,全局取最小值,还要取到所有......呃......我也不知道我在说什么,总之就是那个样子,参考暴力模拟的写法吧......
那就是最大边权最小的生成树 → \rightarrow → 瓶颈生成树 → \rightarrow → 最小生成树。
唐的点就在于 没有继续坚持建图,没有想到瓶颈(最小)生成树。
我甚至写出了暴力模拟中二分的部分......
哦,对,实现上,还有就是要二分找下面的点。
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int h, w, n, r[N], c[N];
vector<pair<int, int>> pos[N];
int fa[N], ans, num;
priority_queue<pair<int, pair<int, int>>> q;
int find(int x){
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
bool merge(int x, int y){
int fx = find(x);
int fy = find(y);
if (fx != fy){
fa[fx] = fy;
num++;
return true;
}
return false;
}
int main(){
freopen("ddlc.in", "r", stdin);
freopen("ddlc.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> h >> w >> n;
for (int i = 1; i <= n; i++){
fa[i] = i;
cin >> r[i] >> c[i];
pos[c[i]].push_back({r[i], i});
}
for (int i = 1; i <= w; i++)
sort(pos[i].begin(), pos[i].end());
for (int i = 1; i <= n; i++){
auto it = lower_bound(pos[c[i]].begin(), pos[c[i]].end(), make_pair(r[i] + 1, 0));
if (it != pos[c[i]].end()){
int dist = it->first - r[i] - 1;
q.push({-dist, {i, it->second}});
}
if (c[i] - 1 >= 1){
auto it = lower_bound(pos[c[i] - 1].begin(), pos[c[i] - 1].end(), make_pair(r[i], 0));
if (it != pos[c[i] - 1].end()){
int dist = it->first - r[i];
q.push({-dist, {i, it->second}});
}
}
if (c[i] + 1 <= w){
auto it = lower_bound(pos[c[i] + 1].begin(), pos[c[i] + 1].end(), make_pair(r[i], 0));
if (it != pos[c[i] + 1].end()){
int dist = it->first - r[i];
q.push({-dist, {i, it->second}});
}
}
}
while (!q.empty() && num < n - 1){
if (merge(q.top().second.first, q.top().second.second))
ans = q.top().first;
q.pop();
}
if (num < n - 1)
cout << -1;
else
cout << -ans;
}
LG9489 ZHY 的表示法
原题链接:ZHY 的表示法
ZYZ提交链接:math
分析
T3......
感觉去掉下取整函数 ⌊ ⌋ \left\lfloor\,\right\rfloor ⌊⌋ 和 mex \operatorname{mex} mex 可以组小专题,有空训练一下吧!毕竟今年 NOIP2025 刚考了,其实那个 mex \operatorname{mex} mex 研究一下性质就行了吧......
哦,关于下取整,花花给了我一个 OI Wiki 的东西。
那,开始看题解吧!
有点恍惚啊......艹,元旦过完了......
形式化一下
f ( y ) = ∑ i = 1 n ⌊ y x i ⌋ f(y)=\sum\limits_{i=1}^{n}{\left\lfloor\frac{y}{x_i}\right\rfloor} f(y)=i=1∑n⌊xiy⌋
转化为询问 [ 1 , p ] [1,p] [1,p] 中有多少个数满足条件。
二分一个最大的 y y y 满足 f ( y ) ≤ p f(y)\le p f(y)≤p,则对于 i ∈ [ 1 , y ] i\in[1,y] i∈[1,y] 的 f ( i ) f(i) f(i),每个数都可以表示 [ 1 , p ] [1,p] [1,p] 中的一个数,对 f ( i ) f(i) f(i) 去重,保留是 x x x 倍数的 i i i。
则可以将数轴划分,每段只取左端点,那就是问 [ 1 , y ] [1,y] [1,y] 中 x x x 倍数的数有多少个,容斥即可。
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 30;
const int INF = 1e18;
int n, l, r, x[N], lcm[1 << 20];
int solve(int p){
int l = 0, r = INF, y = 0;
while (l <= r){
int mid = (l + r) >> 1;
int cnt = 0;
for (int i = 0; i < n; i++){
cnt += mid / x[i];
if (cnt > p)
break;
}
if (cnt > p){
r = mid - 1;
}
else{
y = mid;
l = mid + 1;
}
}
int ans = 0;
for (int S = 1; S < (1 << n); S++){
int cnt = __builtin_popcount(S);
if (lcm[S] > y)
continue;
if (cnt & 1){
ans += y / lcm[S];
}
else{
ans -= y / lcm[S];
}
}
return ans;
}
signed main(){
freopen("math.in", "r", stdin);
freopen("math.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> l >> r;
for (int i = 0; i < n; i++){
cin >> x[i];
}
lcm[0] = 1;
for (int S = 1; S < (1 << n); S++){
int lb = S & -S;
int lst = __builtin_ctz(lb);
int pre = S ^ lb;
if (lcm[pre] == INF || x[lst] == INF){
lcm[S] = INF;
continue;
}
int g = __gcd(lcm[pre], x[lst]);
if (INF / x[lst] < lcm[pre] / g) {
lcm[S] = INF;
}
else{
lcm[S] = lcm[pre] / g * x[lst];
}
}
cout << solve(r) - solve(l - 1);
}
我不理解/ll