2025-2026 XCPC

基本信息

本赛季由 jr-Zlw \texttt{\color{#AA00AA}{jr-Zlw}} jr-Zlw,   Skyzhou \texttt{\color{#0000FF} Skyzhou}  Skyzhou sunchaoyi \texttt{\color{#AA00AA}sunchaoyi} sunchaoyi 组队,全靠大佬带飞~。

中文队名:正在验证该队是否是真人。这可能需要五小时时间。

英文队名:Verifying we are human. This may take five hours.

训练记录

2025.05.02 The 2023 Guangdong Provincial Collegiate Programming Contest

备战省赛,也是组队后的第一次训练。

这一场签到题比较多,一小时以内按顺序过了 A,I,C,D,K。接下来我和 Sky 讨论了一下 M 的做法,确定了 O ( n 2 ) O(n^2) O(n2) 的 DP 维护直径,其间 Zlw 一眼 B 板子题,在 1.5h 一发通过了该题。

之后我和 Zlw 尝试口胡 E,F,没错他基本口胡出来了,大力模板。Sky 提交 M 题 RE,我去瞅了眼,发现三点共线导致分母为 0 0 0,立马帮他改成了叉积写法。之后又 WA,看了半天发现是 INF 开的不够大,红温……好在 3.5h 内通过。

然后我开始写 E 的字典树,写了半天发现巨丑还会运行错误,果断叫上 Zlw 来写,在提交了几发后发现神秘错误,在封榜后通过。之后就是 F,和队友确定了线段树二分写法,但是似乎和他的码风不太一样,于是被踹下来。但是由于写得有点屎,赛时没过,知道赛后 40 min 后通过该题。

最后赛时 8 8 8 题首尾(主要由 Zlw 写了一大半的题 orzorzorz,以及 Sky 的难题攻克)!

F 题有点深刻,自己又写了一遍。终于琢磨出为什么赛时会有这么多队伍过,原来还有两支 log ⁡ \log log 的弱智写法。还是写一下线段树二分的做法吧,借鉴了一下题解,时间复杂度 O ( ∑ k log ⁡ n ) O(\sum k \log n) O(klogn)

#include <bits/stdc++.h>
#define init(x) memset (x,0,sizeof (x))
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define pii pair <int,int>
using namespace std;
const int MAX = 4e6 + 50;
const int MOD = 1e9 + 7;
inline int read ();
int t,n,q,cnt,ls[MAX],rs[MAX],tree[MAX];
class BIT 
{
    int n;vector <ll> c;
    int lowbit (int x) {return x & (-x);}
    public :
    BIT (int n) : n (n),c (n + 1,0) {}
    void modify (int x,int v) {for (int i = x;i <= n;i += lowbit (i)) c[i] += v;}
    ll query (int x) {ll res = 0;for (int i = x;i;i -= lowbit (i)) res += c[i];return res;}
};
void modify (int &cur,int l,int r,int x,int v)
{
    if (!cur) cur = ++cnt,ls[cur] = rs[cur] = tree[cur] = 0;
    tree[cur] += v;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    if (x <= mid) modify (ls[cur],l,mid,x,v);
    else modify (rs[cur],mid + 1,r,x,v);
}
int calc (vector <int> cur)
{
    int res = 0;
    for (auto v : cur) res += tree[v];
    return res;
}
vector <int> next_L (vector <int> cur)
{
    for (auto &v : cur) v = ls[v];
    return cur;
}
vector <int> next_R (vector <int> cur)
{
    for (auto &v : cur) v = rs[v];
    return cur;
}
int search_L (vector <int> cur,int l,int r,int pos)
{
    if (calc (cur) == r - l + 1) return 0;
    if (l == r) return l;
    int mid = (l + r) >> 1;
    if (pos <= mid) return search_L (next_L (cur),l,mid,pos);
    else
    {
        int res = search_L (next_R (cur),mid + 1,r,pos);
        if (!res) return search_L (next_L (cur),l,mid,pos);
        else return res;
    }
}
int search_R (vector <int> cur,int l,int r,int pos)
{
    if (calc (cur) == r - l + 1) return n + 1;
    if (l == r) return l;
    int mid = (l + r) >> 1;
    if (pos > mid) return search_R (next_R (cur),mid + 1,r,pos);
    else
    {
        int res = search_R (next_L (cur),l,mid,pos);
        if (res == n + 1) return search_R (next_R (cur),mid + 1,r,pos);
        else return res;
    }
}
int main ()
{
    t = read ();
    while (t--)
    {
        n = read ();q = read ();cnt = 0;
        vector <int> val (n + 1),col (n + 1),rt (n + 1,0);
        BIT tr (n);
        for (int i = 1;i <= n;++i) col[i] = read (),modify (rt[col[i]],1,n,i,1);
        for (int i = 1;i <= n;++i) val[i] = read (),tr.modify (i,val[i]);
        while (q--)
        {
            int ty = read ();
            if (ty == 1)
            {
                int p = read (),x = read ();
                modify (rt[col[p]],1,n,p,-1);
                col[p] = x;
                modify (rt[col[p]],1,n,p,1);
            }
            else if (ty == 2)
            {
                int p = read (),v = read ();
                tr.modify (p,v - val[p]);
                val[p] = v;
            }
            else
            {
                int st = read (),k = read ();
                vector <int> p;
                for (int i = 1;i <= k;++i)
                {
                    int x = read ();
                    p.push_back (rt[x]);
                }
                int l = search_L (p,1,n,st),r = search_R (p,1,n,st);
                printf ("%lld\n",tr.query (r - 1) - tr.query (l + 1 - 1));
            }
        }
    }
    return 0;
}
inline int read ()
{
    int s = 0;int f = 1;
    char ch = getchar ();
    while ((ch < '0' || ch > '9') && ch != EOF)
    {
        if (ch == '-') f = -1;
        ch = getchar ();
    }
    while (ch >= '0' && ch <= '9')
    {
        s = s * 10 + ch - '0';
        ch = getchar ();
    }
    return s * f;
}

2025.05.15 The 2024 ICPC Asia Hangzhou Regional Contest

上午考完期末,开启暑假生活!

省流: 6 6 6 题收尾。过题顺序 A,K,E,H,M,F。

可能是上午考线代考傻了,签到题写了半小时才过。 A A A 用并查集维护即可,可是一开始写得有点乱,WA 了 2 2 2 次才过。接着队友写 K,不知道怎么回事思路没问题就是过不了。我听完思路直接给他重写了,然后就过了,非常神奇(说明队友码力有点弱,需要加训~)。

接着 Zlw 佬开始敲 B,敲完交了以后才发现把题目理解成了或运算,于是乎,一直只能想到双 log 的做法。我这边看了下 E,一开始认为是 DP,想了一会儿发现更像是贪心。和 Zlw 佬进一步讨论了一下感觉没啥问题。设当前处在 f f f 层,找到 l l l f f f 之下的 r r r 最大的那个,如果不存在,就需要花费额外的能量向上运动。等到达最顶端后在往下降,处理一下剩余的区间,此时不需要额外花费。因此直接可以优先队列维护,从而做到 O ( n log ⁡ n ) O(n \log n) O(nlogn)

Sky 这时候在写 M,写完以后发现题目看错,占了一会儿机时。趁着他在调的时候继续口胡下一题,是我最喜欢的构造!不难想到先取最长的链,设长度为 k k k,于是剩下 [ 1 , k − 1 ] [1,k - 1] [1,k1] 的区间全部能够挂在这条链上。唯一需要考虑的就是有多条长度为 k k k 的链的情况,此时只要前面的区间没有都挂在根节点上就存在解。

M 还有一些问题,于是我把 E,H 这两题都实现了。接下去他俩一起在搞 M,我开始看 F。M 似乎进行数论分析和 ST 维护以后终于过了。F 是图论,容易想到 scc 缩点,难点是处理询问。不过询问又非常特殊,是在一条链上询问,因此就可以通过前缀和处理。但需要注意块内可能询问点并不完整,因此需要更多的处理。突然开窍,然后在比赛结束前 3 分钟通过了!

for (int i = 1;i <= n;++i) ++sz[scc[i]];
for (int i = 1;i <= k;++i)
for (int j = 1;j <= n;++j) 
{
    pre[i][j] = pre[i][j - 1];
    if (scc[a[i][j]] != scc[a[i][j - 1]]) tot[i][j] = 1;
    else pre[i][j] += tot[i][j - 1],tot[i][j] = tot[i][j - 1] + 1;
}
while (q--)
{
        ll id = read (),l = read (),r = read ();
        id = (id + ans) % k + 1;l = (l + ans) % n + 1,r = (r + ans) % n + 1;
        if (scc[a[id][l]] == scc[a[id][r]]) ans = pre[id][r] - pre[id][l - 1] - (tot[id][l] - 1) * (r - l + 1);
        else ans = pre[id][r] - pre[id][l - 1] - (sz[scc[a[id][l]]] - (tot[id][l] - 1)) * (tot[id][l] - 1);
        printf ("%lld\n",ans);
}

总的来说,这场 6 题还是很不错的(似乎能银)。但是罚时过高,速度还是有点慢。看来,还是需要加训滴~

2025.05.16

我开始进一步学习计算几何,争取在省赛前能把这一块的模板弄全。具体内容就放在上面的博客里了。

2025.05.18

自己打了把西安交通大学2025年程序设计竞赛校赛(同步赛),被 F 题硬控了,最后八题收尾。

2025.05.19 The 2025 ICPC Wuhan Invitational Contest

A 签到,I 简单构造,I 无解判断写错 WA 了一发(阿巴阿巴)。

L 算是贪心,容易想到枚举端点位置,但是发现固定最大最小值后中位数位置不确定,于是改为枚举最小值和中位数。队友调了老半天才通过。

F 似乎题解是贪心,但是 Zlw 用背包配合 __int128 通过了,取模没取完整贡献一发罚时。

G 感觉有点典,容易想出把所有颜色分开考虑。这种棋盘就方案数有两种 DP,简单的就直接 O ( n m ) O(nm) O(nm) 遍历;复杂的依赖一种颜色的数量 O ( k ) O(k) O(k),进行 DP 容斥(CF559C)即可。于是想到分块做法,时间复杂度 O ( m n m n ) O(mn \sqrt {mn}) O(mnmn )

M 超绝计算几何,一直调到最后。大致分为两类,到端点的距离以及与原点和垂足形成的直线到线段的交点的距离。设端点是 S , T \text{S},\text{T} S,T,首先做平面 OST \text{OST} OST,做垂足 F F F,若落在直线 OS , OT \text{OS},\text{OT} OS,OT 的那个区域之外,则只需要考虑前一种情况即可,否则两种情况都要考虑。其次需要考虑 ∣ OF ∣ \mid\text{OF}\mid OF 已知时 O F \mathbf{OF} OF 的方向性。最后,需要尤其注意一下精度和垂直的情况。我们写的时候 acos(x) 的参数由于精度问题落在了 [ − 1 , 1 ] [-1,1] [1,1] 之外,然后一直输出 nan,非常令人红温。不过在查看数据并 WA 无数次后终于通过了此题。

2025.05.21 The 2025 ICPC China Zhejiang Province Programming Contest

超多罚时场。

B,I 签到,然后我发现 D 是简单构造,三题一遍过,开局还算比较顺利。

接下去开了 L,由奶龙指认的奶龙一定不是奶龙为出发点,提出拓扑加贪心的算法。我开写,脑抽用 set 来维护最优作为奶龙的节点,可是似乎处理上有很大的细节漏洞,于是一直 WAWAWA,导致接下去的一个半小时没有过题。Zlw 和 Sky 在想 F,讨论出了拆点加 bfs 最短路的做法。被踹下去以后他们提交了三发后通过(WA 是 bfs 后忘记 push 新的节点了)。

这时候我在重构了若干次代码之后突然醒悟,只需要 O ( n ) O(n) O(n) 的拓扑排序即可实现。先处理链,遇到一个点标记为奶龙,指向的下一个点标记为非奶龙,然后再把下一个的下一个点入度减一。剩下为环的部分,如果未标记就记录个数 x x x,一段未标记中奶龙的个数就是 x 2 \frac{x}{2} 2x。再次重写,终于通过。【果然,写奶龙题人也会变唐,阿巴阿巴~~~】

Zlw 在之后尝试 A,作为一个数据结构大神,尝试用分块,莫队以及线段树的结合题切题。Sky 在看 G,我看 M。A 上机尝试并通过样例后提交,发现 TLE,调整分块参数后仍然无法通过。而 M 发现交互毫无意义,把题目转化为了已知与一顶点 P P P 到其它不相邻的顶点构成的线段相交的三角剖分数量,然后还原三角剖分。可惜没什么想法。

G 又想了贪心的想法,于是上机写。由于普通的贪心是 O ( T n k ) O(Tnk) O(Tnk) 的,我微微打表观察以后提出了一个先将每个数增加 max ⁡ ( 0 , k − 100 n n ) \max (0,\frac{k - 100n}{n}) max(0,nk100n) 后剩余部分再贪心的做法(其实严格来说, 100 100 100 应该替换为 max ⁡ l i − min ⁡ l i \max {l_i} - \min {l_i} maxliminli,但是取极限差不多就是 100 100 100),此时经过估算应该能够通过。可是交上去后仍然 TLE,于是接下去的 n 发提交都是再尝试调参卡精度。Sky 弄了半天仍然不行,趁他上厕所的时候,我把他贪心改成优先队列,然后加了快读快写,把常数减小了 5 5 5 倍左右。终于,+10 以 956 ms 极限卡过此题(一共 113 个测试点可还行 qwq)。后来看了题解,发现是要二分操作的倍率,实在是深刻。

还是 6 题首尾,不知道什么时候可以突破捏~

2025.05.22 The 2024 ICPC Asia Shanghai Regional Contest

又难又屎的一场,赛时 5 题,赛后 7 题。

上来就被 I 签到给恶心了好几发,原因就是求的是最大值的模而非模意义下的最大值,因此取模要非常小心。 0 0 0 以及大于模数的情况都需要考虑到,非常容易出错。半小时才通过此题,而且 WA 了整整 7 次(显然是红温了)。

接下来 Sky 秒了博弈论 C,Zlw 开始写 B。但由于一些答案的合并问题,B 一直被硬控。接下来发现 D 是构造,果断将其丢给我。我手玩 D 发现只需要着重考虑最后四位的情况,于是疯狂分讨。上机写 D,发现样例水得一批,于是直接交,喜提 WA。下机思考,Zlw 终于过了 B,然后我发现有几种情况能够更优的构造,果断修改后通过。这时候 2 小时 4 题,除了罚时外到还行。

之后我又发现 H 是构造,于是又开始手玩。他俩在想 G,似乎是和二分中位数相关。H 玩了很久,由于是最优化步数的构造,我似乎没啥完整的想法,于是开始进击 M 计算几何。

M 似乎好做,很快地将问题分为了四类。设非上下表面的点的个数为 n n n(需要去重),然后将上下表面的点映射到二维平面中。于是有:

  1. n = 0 n = 0 n=0 恒有解。
  2. n = 1 n = 1 n=1 判断是否存在一条过定点的直线可以将剩余点归到直线的一侧。直接判断该点是否为凸包上的一点即可。
  3. n = 2 n = 2 n=2 判断过两个定点的圆能够将使得剩余点均在这个圆中。将点分为直线的两侧,然后根据圆周角的大小,一侧各剩下一点(没有的话肯定合法),判断四点共圆即可。特别地,如果点在直线上,则需要在线段上才符合。
  4. n = 3 n = 3 n=3 三点共线则不合法。否则取三点作圆,判断剩余点是否在圆上即可。

想完的时候 Zlw 刚好写完 G,于是我上机贺板子写 M。写完以后一直 WA,各种 corner 写挂,最后又被卡精度,直接写崩溃,直到结束也没过。赛后调了很久很久,然后又不断 hack 自己,最终才诞生了一份稍微好一点的屎。

auto f1 = [&] () -> bool
{
    sp.push_back (P[0]);
    auto hull = convex_hull (sp);
    for (auto [x,y] : hull)
        if (dcmp (x - P[0].x) == 0 && dcmp (y - P[0].y) == 0) return true;
    return false;
};
auto f2 = [&] () -> bool
{
    for (auto x : sp)
        if (on_line (x,P[0],P[1]) && !on_seg (x,P[0],P[1])) return false;
    LD d1 = 1000,d2 = 1000;
    Point P1,P2;
    for (auto x : sp) 
    {
        if (on_line (x,P[0],P[1])) continue;
        if (cross (P[1] - P[0],x - P[0]) > 0) {if (angle (x - P[1],x - P[0]) < d1) P1 = x,d1 = angle (x - P[1],x - P[0]);}
        if (cross (P[1] - P[0],x - P[0]) < 0) {if (angle (x - P[1],x - P[0]) < d2) P2 = x,d2 = angle (x - P[1],x - P[0]);}
    }
    if (d1 == 1000 || d2 == 1000) return true;
    Point F1 = foot (P1,P[0],P[1]),F2 = foot (P2,P[0],P[1]);
    if (dcmp (dot (F1 - P[0],F1 - P[1])) > 0 && dcmp (dot (F2 - P[0],F2 - P[1])) > 0) return false;
    Circle C1 = triangle_circum (P[0],P[1],P1),C2 = triangle_circum (P[0],P[1],P2);
    return in_cir (C1,P2) && in_cir (C2,P1);
};
auto f3 = [&] () -> bool
{
    if (dcmp (cross (P[0] - P[1],P[0] - P[2])) == 0) return false;
    Circle C = triangle_circum (P[0],P[1],P[2]);
    for (int i = 3;i < P.size ();++i)
    if (dcmp (len (P[i] - C.O) - C.r) != 0) return false;
    for (auto x : sp)
    if (!in_cir (C,x)) return false;
    return 1;
};

事实证明,还是要谨慎开计算几何。赛后发现我精准的选到了 H,M Medium hard \text{Medium hard} Medium hard,而跳过了中间的 F,J(非常离谱,看都没看)。看来策略还是需要在接下去进一步调整!

2025.05.23

补题,发现 H 最后构造出来剩余 . 的个数不会超过四个。于是就开始贪心构造,调整 6 种情况的优先级,试着试着突然发现对了。唯一的坑点就是要小心同色连成连通块,直接暴力判断后调整。放一下屎山代码:

int main ()
{
    n = read ();int ans = 0;
    vector <vector <char>> a (n + 5,vector <char> (n + 5,'.'));
    vector <vector <char>> b (n + 5,vector <char> (n + 5,'.'));
    auto check = [&] (int x,int y) -> bool {return !(x < y || x <= 0 || y <= 0 || x > n || a[x][y] != '.');};
    auto same = [&] (char ch,int x,int y) -> bool {return ch == a[x][y - 1] || ch == a[x][y + 1] || ch == a[x - 1][y - 1] || ch == a[x - 1][y] || ch == a[x + 1][y] || ch == a[x + 1][y + 1];};
    for (int i = n;i;--i)
    {
        for (int j = 1;j <= i;++j)
        {
            if (i == n && j == 1) continue;
            if (check (i,j) && check (i,j + 1) && check (i - 1,j - 1))
            {
                while (same (char (op + 'A'),i,j) || same (char (op + 'A'),i,j + 1) || same (char (op + 'A'),i - 1,j - 1)) ++op,op %= 26;
                a[i][j] = a[i][j + 1] = a[i - 1][j - 1] = char (op + 'A');
                ++ans;continue;
            }
            if (check (i,j) && check (i,j + 1) && check (i - 1,j + 1))
            {
                while (same (char (op + 'A'),i,j) || same (char (op + 'A'),i,j + 1) || same (char (op + 'A'),i - 1,j + 1)) ++op,op %= 26;
                a[i][j] = a[i][j + 1] = a[i - 1][j + 1] = char (op + 'A');
                ++ans;continue;
            }
            if (check (i - 1,j - 2) && check (i - 1,j - 1) && check (i,j))
            {
                while (same (char (op + 'A'),i - 1,j - 2) || same (char (op + 'A'),i - 1,j + 1) || same (char (op + 'A'),i,j)) ++op,op %= 26;
                a[i - 1][j - 2] = a[i - 1][j - 1] = a[i][j] = char (op + 'A');
                ++ans;continue;
            }
            if (check (i,j) && check (i - 1,j - 1) && check (i - 2,j - 1))
            {
                while (same (char (op + 'A'),i,j) || same (char (op + 'A'),i - 1,j - 1) || same (char (op + 'A'),i - 2,j - 1)) ++op,op %= 26;
                a[i][j] = a[i - 1][j - 1] = a[i - 2][j - 1] = char (op + 'A');
                ++ans;continue;
            }
            if (check (i,j) && check (i - 1,j) && check (i - 1,j + 1))
            {
                while (same (char (op + 'A'),i,j) || same (char (op + 'A'),i - 1,j) || same (char (op + 'A'),i - 1,j + 1)) ++op,op %= 26;
                a[i - 1][j] = a[i - 1][j + 1] = a[i][j] = char (op + 'A');
                ++ans;continue;
            }
            if (check (i - 1,j) && check (i,j) && check (i - 2,j - 1))
            {
                while (same (char (op + 'A'),i,j) || same (char (op + 'A'),i - 1,j) || same (char (op + 'A'),i - 2,j - 1)) ++op,op %= 26;
                a[i - 1][j] = a[i][j] = a[i - 2][j - 1] = char (op + 'A');
                ++ans;continue;
            }
        }
    }
    for (int i = 1;i <= n;++i)
    {
        for (int j = 1;j <= n - i;++j) putchar (' ');
        for (int j = 1;j <= i;++j) 
        {
            putchar (a[i][j]);
            putchar (j == i ? '\n' : ' ');
        }
    }
    return 0;
}

2025.05.24

仍然是调整日。昨天看其它队伍 vp 的时候发现自己的数论实在是太差了,遂补一下 exgcd。

求满足 ∀ i ∈ [ 1 , n ] , n ( n + 1 ) 2 ≡ 0 ( m o d p i ) \forall i \in [1,n],\frac{n(n + 1)}{2} \equiv 0\pmod {p_i} i[1,n],2n(n+1)0(modpi) 的最小正整数 n n n

l = 2 × lcm ⁡ ( p 1 , p 2 , ⋯   , p n ) l = 2\times \operatorname{lcm} (p_1,p_2,\cdots,p_n) l=2×lcm(p1,p2,,pn)。转换为最小化 n n n,使得 n ( n + 1 ) ≡ 0 ( m o d l ) n(n + 1) \equiv 0 \pmod l n(n+1)0(modl) 成立。

由于 gcd ⁡ ( n , n + 1 ) = 1 \gcd (n,n + 1) = 1 gcd(n,n+1)=1,因此 l l l 的一种因子只会分给 n n n n + 1 n + 1 n+1 其中一个。由于 l l l 的因子数量最多为 15 15 15 个,因此状压枚举即可。

对于当前状态 s t st st,令 x = ∏ i ∈ s t p i , y = ∏ j ∈ s t ∁ p j x = \mathop{\prod}_{\substack{i \in st}} p_i,y = \mathop{\prod}_{\substack{j \in st^\complement}} p_j x=istpi,y=jstpj,则 n = a x , n + 1 = b y n = ax,n + 1 = by n=ax,n+1=by,作差可知 − a x + b y = 1 -ax + by = 1 ax+by=1。由于 gcd ⁡ ( a , b ) = 1 \gcd (a,b) = 1 gcd(a,b)=1,方程有解,直接跑 exgcd,然后求 min ⁡ { a x } \min \{ax\} min{ax} 即可。

终于把上个赛季重庆站的题目给补了。(以下证明部分参考 CCPC2024 重庆_补题记录ADFGH)

命题

b = w 2 x 5 y b = w2^x5^y b=w2x5y,则最优条件下 d d d 一定可以表示为 w 2 x ′ 5 y ′ w2^{x\prime}5^{y\prime} w2x5y(其中 w , z w,z w,z 不再含有 2 , 5 2,5 2,5 的幂次)。

证明

d = z 2 x ′ 5 y ′ d = z2^{x\prime}5^{y\prime} d=z2x5y,则 a b + c d = a z 2 x ′ 5 y ′ + w c 2 x 5 y w z 2 x + x ′ 5 y + y ′ \frac{a}{b} + \frac{c}{d} = \frac{az2^{x\prime}5^{y\prime} + wc2^x5^y}{wz2^{x + x\prime}5^{y + y\prime}} ba+dc=wz2x+x5y+yaz2x5y+wc2x5y。接下来处理分子,由于最后是有限小数,一定存在 k k k 使得 a z 2 x ′ 5 y ′ + w c 2 x 5 y = k w z az2^{x\prime}5^{y\prime} + wc2^x5^y = kwz az2x5y+wc2x5y=kwz 成立。

c , k c,k c,k 看作未知数,写成 exgcd 的标准形式:

( − w 2 x 5 y ) × c + w z × k = a z 2 x ′ 5 y ′ (-w2^x5^y) \times c + wz \times k = az2^{x\prime}5^{y\prime} (w2x5y)×c+wz×k=az2x5y

有解当且仅当 gcd ⁡ ( − w 2 x 5 y , w z ) = w ∣ a z 2 x ′ 5 y ′ \gcd(-w2^x5^y,wz) = w \mid az2^{x\prime}5^{y\prime} gcd(w2x5y,wz)=waz2x5y,也就是 w ∣ a z w \mid az waz。由于 gcd ⁡ ( a , b ) = 1 \gcd (a,b) = 1 gcd(a,b)=1,则 gcd ⁡ ( a , w ) = 1 \gcd (a,w) = 1 gcd(a,w)=1,因此得到 w ∣ z w \mid z wz

同理,把 a , k a,k a,k 当作未知数,可以得到 z ∣ w z \mid w zw

综上, z = w z = w z=w 成立。

因此, a b + c d = a 2 x ′ 5 y ′ + c 2 x 5 y w 2 x + x ′ 5 y + y ′ \frac{a}{b} + \frac{c}{d} = \frac{a2^{x\prime}5^{y\prime} + c2^x5^y}{w2^{x + x\prime}5^{y + y\prime}} ba+dc=w2x+x5y+ya2x5y+c2x5y。由于最后是有限小数,所以可以进一步把和表示为 k w w 2 x + x ′ 5 y + y ′ = k w 2 b d \frac{kw}{w2^{x + x\prime}5^{y + y\prime}} = \frac{kw^2}{bd} w2x+x5y+ykw=bdkw2。枚举 d d d 中的 x ′ , y ′ x^{\prime},y^{\prime} x,y,然后求不定方程

b × c − w 2 × k = − a d b \times c - w^2 \times k = -ad b×cw2×k=ad

直接 exgcd 后求出 c c c 的最小值即可。

2025.05.25 第十届中国大学生程序设计竞赛 济南站(CCPC 2024 Jinan Site)

题目好难,就做出 4 题,倒闭!

A,J 签到,但是 A 被我 WA 了一发。之后想 F,Zlw 用了数论做法,还用到了莫比乌斯反演,似乎复杂化了,WA 了好几次以后才过(应该已经是 2.5 h 左右了)。

我看了 E,感觉是个超级分类讨论题,于是开始疯狂推公式。Sky 看 B,是个模拟+暴力题,但是不好写。E 我分了 7 类,感觉差不多了就上机写。由于涉及高精度,于是果断使用 Python。样例真的水的一批,过了样例交然后喜提 WA。

静态调试无果,于是下机看 I 换换脑子,Sky 上机写 B。I 构造容易想到自底往上,同一个子树内的点可以直接合并,然后想到链的做法不太好搞。这时候 Sky 过了 B,于是我就没再细想,把题丢给他俩,然后调 E 去了。

事实证明,这是这场比赛的败笔。接下来的时间内,E 一直被形如 ABAB...A 需要对最后一个 A 调整的 case 所困扰,而他俩直接把 I 想复杂,在做树上 DP。于是一直红温到比赛结束。


后来才发现,E 的 ABAB...A 的调整还需要细化。假设直接按照这个方案会浪费掉 x x x 的距离,则有:

  • B 最多可以移掉 min ⁡ ( x , ⌊ D X + Y ⌋ × Y ) \min (x,\lfloor\frac{D}{X + Y}\rfloor \times Y) min(x,X+YD×Y)

  • 变为 AA...ABAB 的形式 B 最多有 min ⁡ ( D − ⌊ D X ⌋ × X , ⌊ D X ⌋ × Y ) \min (D - \lfloor\frac{D}{X}\rfloor \times X,\lfloor\frac{D}{X}\rfloor \times Y) min(DXD×X,XD×Y)

最终代码:

def up (x,y) : return (x - 1) // y + 1
def solve (A,B,C,X,Y,D) :
    if D <= X : return A
    if D <= X + Y : return min (A + B * (D - X),A * up (D,X),A * (D // X) + B * (D % X))
    ans = A * up (D,X) #AA...A
    if D % X <= Y : ans = min (ans,(D // X) * A + B * (D % X)) #AA...B
    else : ans = min (ans,(D // X) * A + B * Y + (D % X - Y) * C) #AA...BC
    ans = min (ans,A + B * Y + (D - X - Y) * C) #ABC
    if D % (X + Y) > X : ans = min (ans,(D // (X + Y)) * (A + B * Y) + A + B * (D % (X + Y) - X)) #ABAB...AB
    ans = min (ans,D // X * A + min (D - D // X * X,D // X * Y) * B + (D - D // X * X - min (D - D // X * X,D // X * Y)) * C) # AA..ABAB..
    ans = min (ans,(D // (X + Y)) * (A + B * Y) + A - B * min (D // (X + Y) * Y,X - D % (X + Y))) #ABAB...A
    ans = min (ans,(D // (X + Y)) * (A + B * Y) + C * (D - (X + Y) * (D // (X + Y)))) #ABAB...C
    return ans

而 I,那种链的情况也很好做,直接记录下剩余的点然后往上传即可。注意如果一个子树内,优先合并单点,再合并向上传过的点(因为单点不能形成自环)。赛后 Sky 写了 I,一发通过;我也在发现 corner case 以后 WA 了几发后通过。简直破大防!

C 纯构造竟然没发现,感觉非常好做。POP n GOTO n + 1; PUSH n GOTO n 就能形成链,POP n GOTO n + 1; PUSH n GOTO 1 就能翻倍,于是这道题做完了。

void dfs (ll x)
{
    if (!x) return ;
    if (x / 2 % 2 == 1)
    {
        dfs (x / 2 - 1);++cnt;
        printf ("POP %d GOTO %d; PUSH %d GOTO %d\n",cnt,cnt + 1,cnt,1);
    }
    else
    {
        dfs (x - 2);++cnt;
        printf ("POP %d GOTO %d; PUSH %d GOTO %d\n",cnt,cnt + 1,cnt,cnt);
    }
}

2025.05.26 The 2024 ICPC Southeastern Europe Regional Contest (SEERC 2024)

做点欧洲的区域赛来换换脑子。

开局 Zlw 发现 A 是 n 2 n^2 n2 的做法,于是不需要换根 DP 直接暴力。我在看 D,感觉变种的 Nim 游戏并不是那么好做,但 Sky 发现后手是需要连续操作 n n n 轮,与堆数相同,那么这道题瞬间变唐。于是立刻开写,但被全是 0 0 0 的 corner case 淦了一发罚时。

在 A 通过之后,我发现 G 是一个简单 DP,直接开写,一发通过。之后 Sky 让我看看 J,如果是极值的情况答案很简单,然后发现如果是被最大最小值加在中间时,只需要多一次操作就能将其归约到前一种情况,于是火速过 J。Zlw 在想 L,猜了一个想法并手搓平衡树,竟然一发通过,不知道有没有想复杂。

大家一起看 H,猜测是贪心但是又有点不会证明。这时候 Zlw 想到了一个网络流做法并保证了正确性,由于我和 Sky 对这题都没啥想法,于是就让 Zlw 开写(因此也在与正解越走越晚)。好不容易写完以后,一交 TLE,这下完蛋,被 m m m 很小的点卡了,也没法优化。好,这下被真的卡住了,已经将近 1.5 h 没有过题。

好在 Zlw 重新思考贪心做法,并用尝试优先队列去维护,在四小时不到一点的时候通过。我和 Sky 在开 K,我提出维护最初每一个字符所扩展到的区间 l i , r i l_i,r_i li,ri,Sky 推了推发现是可维护的(虽然要分好几类)。但 Sky 并不是很擅长线段树,于是我先开始上机写区间加和乘,然后让他报给我区间更新的具体内容。本来是报着打完这道题还要调试一万年的,但是我稍微修改了一下我查询写挂的地方,之后竟然直接过样例。直接交!RE!噢是有个地方没开 long long!再交!AC!我们狂喜!

还剩下 20 min,尝试开 C 交互,但是没啥想法,最后 7 题收尾!


C 从集合与集合之间的询问出发,通过二分找到能与集合连边的单点。具体来说, L L L R = R 1 ∪ R 2 R = R_1 \cup R_2 R=R1R2 获得 a + c a + c a+c,然后二分右侧获得 R 1 , R 2 R_1,R_2 R1,R2。之后进行进一步地询问, L ∪ R 1 L\cup R_1 LR1 R 2 R_2 R2 询问获得 b + c b + c b+c,, L ∪ R 2 L \cup R_2 LR2 R 1 R_1 R1 询问获得 a + b a + b a+b。若 a + b + a + c = b + c a + b + a + c = b + c a+b+a+c=b+c,则 a = 0 a = 0 a=0,也就说明 R R R 中只有 R 2 R_2 R2 L L L 有直接连边。因此 n n n 轮每次获得一个直接相连的点,询问次数在 n + 2 n log ⁡ n n + 2n \log n n+2nlogn

2025.05.27 The 2024 ICPC Central Europe Regional Contest

开局 B,C,D 签到。然后看 L,搜索题的变种,一眼猜测需要再加一个维度表示朝向,但是不太想写,丢给 Zlw 了。

看 I,没想法;看 K,以为是构造,但是发现可能是搜索。发现奇数和偶数的位置一定有一种是需要全填的,但是剩余的位置还有 32 个,直接暴力不可过,于是开始各种乱搞。但是怎么尝试都 WA,于是开摆(

Sky 成功把 I 做出来了,真是太有实粒了!先入为主的会去想行与行之间的关系,可是如果考虑列,对于第 i i i 个位置,进行变换 k → k + 1 k \to k+1 kk+1,即 S k [ i ] = S k + 1 [ P ( i ) ] S_k[i] = S_{k+1}[P(i)] Sk[i]=Sk+1[P(i)],将这条约束在 k = 1 , 2 , … , k − 1 k=1,2,\ldots,k-1 k=1,2,,k1 都写出来:
( S 1 [ i ] S 2 [ i ] ⋮ S k − 1 [ i ] ) → ( S 2 [ P ( i ) ] S 3 [ P ( i ) ] ⋮ S k [ P ( i ) ] ) \begin{pmatrix} S_1[i] \\ S_2[i] \\ \vdots \\ S_{k-1}[i] \end{pmatrix} \to \begin{pmatrix} S_2[P(i)] \\ S_3[P(i)] \\ \vdots \\ S_k[P(i)] \end{pmatrix} S1[i]S2[i]Sk1[i] S2[P(i)]S3[P(i)]Sk[P(i)]

也就是说,用第 1 , ⋯   , k − 1 1,\cdots,k−1 1,,k1 轮的列向量去匹配第 2 , ⋯   , k 2,\cdots,k 2,,k 轮的列向量,贪心找最小值即可。

Zlw 继续开 F 数据结构,上机写着写着感觉太麻烦了,又开摆(

最后 5 题收尾了(太累了,开启休整模式 qwq)。赛后还是看了下 K 别人的代码,发现就是疯狂减枝的爆搜,这种题都能上区域赛?有点离谱了!

2025.05.29 The 2023 ICPC Asia Jinan Regional Contest

D 签到,鹊巢原理之后就会异常好做(Zlw 佬一开始没看出来,差点写成数位 DP)。Sky 猜了一个 I 的结论,一发通过!我看 A,一下子没想法,和 Zlw 讨论了一下突然会了,只要贪心还原,然后只要有一个右括号的右侧存在一个左括号,并且中间是合法的即可。感觉很对,丢给 Zlw 去写了。

尝试看 K,猜想二分,但是 check 很难写。Zlw 佬看了题,一眼中位数最优,然后尝试用对顶堆去维护,似乎多了一个 log ⁡ \log log,但是好在一发通过!接着 Sky 喂给我一个 G 题的做法,直接上机写并查集,写完后 WA,我思考了一会儿想到 1010 1100 这种既互斥又互补的做法,本来想要特判,但是发现这是一类没有考虑到的情况。Zlw 即时的提出了这就是 2-SAT,直接上扩展域并查集即可。修了好久,总算通过了。其间红温了好久,下机缓了缓,而趁着这个时间他俩讨论出了 E 的网络流做法,并一发 AC,真的太有实粒了!

最后开了 M,想到先求凸包,然后枚举一个基准点,用极角排序和双指针来维护答案,时间复杂度 O ( n 2 log ⁡ n ) O(n^2 \log n) O(n2logn)。想得非常正确,但由于对极角排序非常的不熟悉,用 atan2 超时了,然后想要改成叉乘却又发现不对,还剩一个小时但是也没调出来,成罪人了(

好在六题收尾,并且只有一发罚时!

赛后补题,发现 M 的致命错误:

  • 制作模板的时候写的是 0-vector,而一开始自己写的却是 1-vector。

  • 直接预处理了 atan2 后再排序,把超时问题解决了,这个函数是真的慢啊!!!

  • 判断点是否在三角形内用的是角度的做法,但是有精度误差导致一直 WA 掉。最后改成看穿入穿出的奇偶性之后就对了。

int in_Poly (vector <Point> P,Point A)
{
    int cnt = 0,n = P.size ();
    for (int i = 0;i < n;++i)
    {
        int j = (i + 1) % n;
        if (on_seg (A,P[i],P[j])) return 2;// on the edge
        if (A.y >= min (P[i].y,P[j].y) && A.y < max (P[i].y,P[j].y)) // the intersection is on the right
            cnt += dcmp (((A.y - P[i].y) * (P[j].x - P[i].x) / (P[j].y - P[i].y) + P[i].x) - A.x) > 0;
    }
    return cnt & 1;
}

2025.05.30 第九届中国大学生程序设计竞赛 桂林站(CCPC 2023 Guilin Site)

省赛前最后一训!

G 题面写得实在有点一言难尽,读懂题目后发现是弱智题,速速通过。接着又很快的签完 M。

之后看了 K,发现 n × m ≤ 180 n \times m \le 180 n×m180 的数据范围很诡异,发现可以针对 n n n 较小和 m m m 较小写暴力,调了一会儿三发通过(之后看题解发现答案数量有限,直接用 map 跑暴力即可)。

之后看 B,C,发现都不好做,于是开始坐牢。B 的贪心情况很多,Sky 一直在红温,我和 Zlw 尝试做 C。C 的式子很是特殊,由于异或是不进位加法,所以 lcm ⁡ { a i j } ∣ ⨁ j = 1 m a i j \operatorname{lcm} \{a_{i_j}\} \mid \bigoplus_{j=1}^m a_{i_j} lcm{aij}j=1maij 成立只有 ⨁ j = 1 m a i j = 0 \bigoplus_{j=1}^m a_{i_j} = 0 j=1maij=0 ⨁ j = 1 m a i j = lcm ⁡ { a i j } = max ⁡ { a i j } \bigoplus_{j=1}^m a_{i_j} = \operatorname{lcm} \{a_{i_j}\} = \max \{a_{i_j}\} j=1maij=lcm{aij}=max{aij}。对于第一种情况,直接跑线性基,答案为 2 n − r 2^{n - r} 2nr r r r 为秩。对于第二种情况,先用 log ⁡ \log log 复杂度预处理每一个最大值的约数,然后两边同时异或上最大值就规约为第一种情况,再跑线性基即可,放个代码:

int main ()
{
    vector <vector <int>> d (200001);
    for (int i = 1;i <= 200000;++i)
        for (int j = i;j <= 200000;j += i) d[j].push_back (i);
    t = read ();
    while (t--)
    {
        n = read ();
        vector <int> cnt (n + 1,0);Basis <int> basis (n,20);
        for (int i = 0;i < n;++i)
        {
            int x = read ();++cnt[x];
            basis.modify (x);
        }
        int ans = (qpow (2,n - basis.query ()) + MOD - 1) % MOD;
        for (int i = 1;i <= n;++i)
        {
            if (!cnt[i]) continue;
            int tot = 0;
            Basis <int> tmp (n,20);
            for (auto v : d[i]) 
                if (cnt[v]) tmp.modify (v),tot += cnt[v];
            ans = (ans + qpow (2,tot - tmp.query ()) % MOD) % MOD;
        }
        printf ("%d\n",ans);
    }
    return 0;
}

之后 Sky 尝试写 B,但是一直在调。我和 Zlw 讨论了 H 并得到了一个感觉相当正确的猜想。Zlw 还看了 I,不过没有什么非常好的想法。

打到后面稍稍有点累,于是 B 没调出来。H 我就最后 10 min 上机尝试写了一下,结果被 corner case 卡了。


屎到底还是要吃的。赛后 Zlw 看了 I 的题解恍然大悟,光速过题;Sky 在发现自己的程序被卡超时后好不容易改成 log ⁡ \log log 并通过了 B;而我,在发现还要记录叶子节点上 1 1 1 的个数(可以合成一个 2 2 2)后也通过了 H。

auto dfs = [&] (auto self,int u,int fa) -> void
{
    w[u] = a[u];one[u] = a[u] == 1;
    for (auto v : ve[u])
    {
        if (v == fa) continue;
        self (self,v,u);
        w[u] += w[v];
        odd[u] = min (odd[u],odd[v]);
        even[u] = min (even[u],even[v]);
        one[u] += one[v];
    }
    if (w[u] & 1) odd[u] = min (odd[u],w[u]);
    else if (w[u] != 0) even[u] = min (even[u],w[u]);
    if (w[u] < k) return ;
    if (w[u] == k) ++ans,w[u] = one[u] = 0,odd[u] = even[u] = INF;
    else if (w[u] > k)
    {
        int del = w[u] - k;
        if (del % 2 == 1 && odd[u] <= del) ++ans,w[u] = 0,odd[u] = even[u] = INF;
        if (del % 2 == 0 && (even[u] <= del || one[u] >= 2)) ++ans,w[u] = one[u] = 0,odd[u] = even[u] = INF;
    }
};

害,只不过赛时啥实力不剩,只剩下红温了……

2025.06.02 The 2025 Guangdong Provincial Collegiate Programming Contest

出征省赛!深圳技术大学的校园真是开放,进出门完全没有人管,校园很大,而且厕所里有空调!

进到机房以后,发现有 vscode,然后监考一会儿说可以用,一会儿又说不可以(笑话)。在延迟了 15 min 左右以后终于开始比赛,好在 PTA 这次没炸。

发现 D 是签到,Zlw 先敲了,然后发现 dev 的 -std=c++14 不能用,改成 c++11,仍然报错!好了,这下直接退化成 c++98,作为一个 auto 选手,直接倒闭(于是接下来,我都拒绝上机。

D 写完后,Sky 开始写模拟 F,写了几发都没过,于是 Zlw 先上机一发过了 G。然后我再听了 Sky 的思路以后,极不情愿的上机开始调,看了半天以后直接重构,一交继续 WA,想了一会儿以后发现思路有问题,加了一个贪心的排序以后再交,还是 WA!我开始红温,再看了很多遍以后发现有个地方忘记写 + 了,赶紧改,终于再 WA6 以后通过,成大罪人了。

之后是 H,发现贪心连边以后直接跑 DP 就能求出所有本质不同的子串,两发通过。然后看了 J,和 Zlw 简单对了思路以后发现用优先队列维护即可。由于我不想再上机写代码,于是继续 push 了 Zlw。

还有将近两小时,看 I,我先想了大概的思路,但是要上机敲代码的时候发现漏考虑了容斥的部分情况。于是 Zlw 继续发力,提出直接暴力考虑三列的情况。写了半天在还有不到半小时以后过了样例,直接交!WA!

坏了,继续调试,发现写得似乎都没问题,继续交了几发,一直到赛后也没过……五题收尾!

本来以为只有 Cu,后来发现 Ag 的比例也有 20 % 20\% 20%,最后 rk62 Ag(还被另一支校队伍从 4 → 6 4 \to 6 46 翻盘,真的是不封榜不会写代码了)。


赛后补题:

  • I 发现看错题了,有一只队伍需要强制选择,而我们在一次次转述题意之后出现了差错,导致没过题的惨剧。也就是说,我们的方法做成了更加复杂的版本,因此我加了点补丁以后直接过了。

  • A Zlw 的思路大致正确,于是赛后交了几发以后通过。其间 WA 时因为某些 long long 和 __int128 的问题,最后跪着接(#define long long __int128) 就过了。

  • 我补了 K,直接上哈希。发现答案递增,然后用哈希判断回文,用哈希和等比数列公式验证是否存在循环节。直接枚举答案以及 [ 1 , i ] [1,i] [1,i] 的询问即可。

Hash dl (s);reverse (s.begin (),s.end ());Hash dr (s);
for (int i = 1;i <= n;++i)
{
    auto check = [&] (int x) -> bool
    {
        if (x == 1) return dl.get (1,i) == ((dl.get (1,1) * (Z <ll,MOD> (1) - dl.get_pw (i))) / (Z <ll,MOD> (1) - base));
        if (x * 2 - 1 >= i)
        {
            Z <ll,MOD> dx = dl.get (2 * x - i,x),dy = dr.get (n - i + 1,n - x + 1);
            return dx == dy;
        }
        int r = x * 2 - 1;
        Z <ll,MOD> dx = dl.get (1,r),dy = dr.get (n - r + 1,n);
        if (dx != dy) return false;
        --r;
        dx = dl.get (1,r) * (Z <ll,MOD> (1) - (dl.get_pw (r) ^ (i / r))) / (Z <ll,MOD> (1) - dl.get_pw (r));
        dx = dx * dl.get_pw (i % r) + dl.get (1,i % r);
        return dx == dl.get (1,i);
    };
    for (int j = res;j <= i;++j)
        if (check (j)) {res = j;break;}
    ans ^= 1ll * i * res;
}

2025牛客暑期多校训练记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值