做题笔记(一)

难度大多都在 *2400 - *2700

标签:线段树

【1 / 100】

开 26 个线段树,然后直接贪心填就可以了。

  • CF1656F

标签:推式子

首先题目的式子可以化成 (ai+t)(aj+t)t2

这一步是帮助得到贪心的连边方案的,但是我推到这里后去想直接构造了。

然后可以得到一个贪心的方案,从小到大排序,负数向最大的正数(后缀)连边,正数向最小的(前缀)连边。

直接计算贡献即可。

  • CF1089I

标签:析合树

析合树就是用来处理这一种值域连续段的问题的。

OI-wiki 上对于析合树的讲解。

我们回顾一下题目,要求不存在长度为 [2,n1] 之间的连续段,换句话说,就是根节点下恰有 n1 个节点,且没有任何一个子段是题目中要求的连续段。

我们记这样的答案为 An 也就是我们要求的答案。直接解决是 Hard 的,我们考虑容斥一下,算存在连续段的方案数。

首先需要分类讨论:

根是合点#

不妨以递增顺序的合点为例,显然递减的情况是一样的。

Ix 表示前 x 位有多少种填法,使得任意一个前缀都不是连续段。

Ix=i=1x1Ii(xi)!

前面方案乘上后面随便的方案之和即可。

这一种情况的答案就是 2i=1nIi(ni)!

根是析点#

这一步我们要知道子树中任意一个子段都不是连续段,这个就是我们之前设的 A 数组,同样考虑递推求出来。

首先要枚举有几个儿子,然后乘上这些段的答案即可。

那么我们还需要 DP 计算出 n 个点放在 j 段中的方案。

然后递推出 A 数组即可。

代码#

点击查看代码
#include <bits/stdc++.h>
#define int long long

#define F(i, a, b) for (int i = (a); i <= (b); i++)
#define dF(i, a, b) for (int i = (a); i >= (b); i--)
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int N = 405, M = (N << 1), inf = 1e16;
int mod, n, m, A[N], I[N], fac[N], B[N][N];
signed main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n >> mod;
    fac[0] = 1;
    F(i, 1, 400) I[i] = fac[i] = fac[i - 1] * i % mod;
    F(i, 2, 400)
        F(j, 1, i - 1) 
            I[i] = (I[i] - I[j] * fac[i - j] % mod + mod) % mod;
    B[0][0] = 1;
    F(i, 1, 400) F(j, 1, i) F(k, 1, i)
        B[i][j] = (B[i][j] + B[i - k][j - 1] * fac[k] % mod) % mod;
    A[1] = 1, A[2] = 2, A[3] = 0;
    F(i, 4, 400) {
        A[i] = fac[i];
        F(j, 1, i - 1)
            A[i] = (A[i] - 2 * I[j] * fac[i - j] % mod + mod) % mod;
        F(j, 4, i - 1)
            A[i] = (A[i] - B[i][j] * A[j] % mod + mod) % mod;
    }
    F(i, 1, n) {
        int x;
        cin >> x;
        cout << A[x] << '\n';
    }
    return 0;
}
  • CF940F

标签:莫队

带修莫队。

记录 l,r,time 然后在跳指针的时候加入时间轴的改变即可,单点修改可以直接 swap 被修改的数字和修改的数字,这样可以实现两次修改就是撤销的操作。

统计答案可以直接暴力,就是 O(nn) 的,一开始想到的是这个,但是不知道为什么后来想要写值域分块了 233。

  • CF229E

标签:DP。

首先,前 n 大的是必须要选的,然后有一些是可选的,在这些当中选择 cnt 个的概率可以 DP 求出。

fi,j 表示前 i 个名字,选了 j 个可选的概率。

如果当前没有可选的,则 fi,j=fi1,jCkxx 是必选的个数。

否则加入一个转移:fi,j=fi1,j1Ckx+1

  • CF954H

标签:枚举

首先枚举 LCA,如果是直链就直接算,O(n2),否则的话就需要枚举两个长度,O(n3)

这一部我们可以写出答案的式子,发现最后要处理一个巻积的形式,但是这一步是可以 O(n2) 提前递推计算的。

  • CF1375E

【2 / 100】

标签:构造

有点幽默的构造,怎么被直接排序过了。

首先得到所有逆序对,然后按照右端点排序,如果相同按照左端点的值排序,否则按照左端点升序。

首先,我们显然要使得第 n 个位置满足条件,然后转化为一个子问题,要求大小关系不变,然后刚刚第一步就是缩减为子问题,后面的就是保证大小关系不变。

所以本质相同。

  • CF1468I

标签:数学

【3 / 100】

首先考虑 a×dx1+b×dx2=x 固定的情况。

那么可以得到所有可行的 a,b,记 G=gcd(dx1,dx2)

{a=a0+tdx2Gb=b0tdx1G

带入到另一个式子里可以得到:

(a0+tdx2G)dy1+(b0tdx1G)dy2

那么发现 t 的系数是 C=|dx2dy1dx1dy2|G,也就是我们得到了 x 固定的时候 y 的步长。

那么 x 的步长是显然的,为 G

那么要不重不漏,也就是要恰好有 CG 个数字填补空缺。

  • CF449C

标签:数学。

首先我们可以把质数加进去,取出所有没有被选过的倍数,然后若为偶数个直接输出,奇数个就把 2p 留下,其他输出,这样的话所有奇数都会汇聚到 2 上,显然是最优的。

所以倒序枚举。

  • CF1280D

标签:树形 DP。

观察复杂度,是一个树上背包的形式。

那么我们设 fi,j 表示 i 点所在子树内划分了 j 个连通块时最多有几个是符合要求的,符合要求数量相同时要剩下的 wb 最大。

然后树上背包合并的时候讨论要不要合并两个连通块即可。

  • CF1253F

标签:最小生成树

首先以所有充电桩为原点跑最短路,求出每个点到充电桩的距离 dis

那么对于一条边,能通过的代价就是 cw+disu+disv。更改边权,每次询问就是求最小生成树上两点之间的距离最大值。

  • CF1076F

标签:DP。

首先显然可以设出 DP 状态:fi,0/1 表示前 i 个,以 0/1 结尾最少几个数字。

然后转移:

假设之前有 a0,现在要加入 x 个,每一个 1 可以隔开 k0,所以是 a+xky

  • CF1717F

标签:网络流

zyz 是不是 【4 / 100】。

首先转化题意,变成一个入度和出度的关系,然后变成只和入度有关,相当于是每一条边选择一个点 +2

直接跑网络流,然后判断无解需要再跑一次。

  • CF338E

标签:线段树

不是我怎么不会唐题。

首先转化一下 b,要求 a 中的元素排序后对应位置大于等于 b,这一步直接改成在 ai1,在 bi+1,权值线段树维护前缀和数组全局最小值即可。

  • CF1468G

标签:计算几何

首先从右向左扫,然后维护当前斜率最小的地方,若左端点和眼睛的斜率小于等于当前最小斜率,那么更新并加上答案,就是计算一下线段和当前最小斜率的交点,做完了。

  • CF1209F

标签:bfs

比较 Tricky 的一个题。

首先拆点,变成每条边都只有一个数字,那么显然要求位数越少越好,直接 bfs。

但是要求 [0,9] 依次转移,这可以用 vector 实现一次转移多个点。

  • CF1716F

标签:数学,生成函数

【5 / 100】

首先是正解:

a=m2,b=ma

i=1nik(ni)biani=i=1nj=1k{kj}ij_(ni)biani=j=1k{kj}j!i=1n(ni)(ij)biani=j=1k{kj}(nj)j!i=1n(njij)biani=j=1k{kj}(nj)j!bji=1n(njij)bijani=j=1k{kj}(nj)j!bj(a+b)nj

然后我们可以给出一个生成函数做法。

先不管 k 次方的事情,设出生成函数为 F(x)=(a+bx)n

然后我们把 xex 代入,答案就是 k![xk]F(ex)

使用多项式操作即可达到单次 O(klogk)

  • CF1651E

标签:图论

鱼鱼蒸题。

原图由若干个偶环组成,那么对于每个环分别计算贡献,枚举环上的一段区间,然后算出要能包含这一段的 l,r,L,R 的对应的最小区间,然后又不能包含这段区间左右的点,所以要去掉一部分,然后乘起来再乘上区间长度的一半即可。

优美的代码实现。

#include <bits/stdc++.h>
#define int long long

#define F(i, a, b) for (int i = (a); i <= (b); i++)
#define dF(i, a, b) for (int i = (a); i >= (b); i--)
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int N = 6005, M = (N << 1), inf = 1e16, mod = 1e9 + 7;
int ans, n, m, cnt, vis[N], cir[N];
vector<int> G[N];
void dfs(int u) {
    vis[u] = 1; cir[++cnt] = u;
    for (auto i : G[u]) if (!vis[i]) dfs(i);
}
int mx1 = 0, mn1 = inf, mx2 = 0, mn2 = inf;
void work(int x) {
    if (x <= n) mx1 = max(mx1, x), mn1 = min(mn1, x);
    else mx2 = max(mx2, x), mn2 = min(mn2, x);
}
void ckmax(int &x, int y) { if (y > x) x = y; }
void ckmin(int &x, int y) { if (y < x) x = y; }
signed main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n;
    m = n * 2;
    F(i, 1, m) {
        int u, v;
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    F(i, 1, n) {
        if (!vis[i]) {
            mx1 = 0, mn1 = inf, mx2 = 0, mn2 = inf, cnt = 0;
            dfs(i);
            F(j, 1, cnt) cir[j + cnt] = cir[j];
            F(j, 1, cnt) work(cir[j]);
            ans += mn1 * (n - mx1 + 1) * (mn2 - n) * (n * 2 - mx2 + 1) * cnt / 2;
            F(j, 1, cnt) {
                mx1 = 0, mn1 = inf, mx2 = 0, mn2 = inf, work(cir[j]);
                F(k, j + 1, j + cnt - 2) {
                    work(cir[k]);
                    int val = (k - j + 1) / 2, x[2] = {j == 1 ? cnt * 2 : j - 1, k + 1};
                    int d1 = 1, u1 = n, d2 = n + 1, u2 = n * 2;
                    F(p, 0, 1) {
                        if (cir[x[p]] >= mn1 && cir[x[p]] <= mx1 || cir[x[p]] >= mn2 && cir[x[p]] <= mx2) {val = 0; break;}
                        if (cir[x[p]] <= n) {
                            if (cir[x[p]] < mn1) ckmax(d1, cir[x[p]] + 1);
                            if (cir[x[p]] > mx1) ckmin(u1, cir[x[p]] - 1);
                        } else {
                            if (cir[x[p]] < mn2) ckmax(d2, cir[x[p]] + 1);
                            if (cir[x[p]] > mx2) ckmin(u2, cir[x[p]] - 1);
                        }
                    }
                    ans += (mn1 - d1 + 1) * (u1 - mx1 + 1) * (mn2 - d2 + 1) * (u2 - mx2 + 1) * val;
                }
            }
        }
    }
    cout << ans;
    return 0;
}
  • CF1394C

标签:三分。

【6 / 100】

首先题目的要求实际上就是 BN 的个数分别相等,那么已知两者个数的时候可以直接分讨然后计算,时间复杂度 O(n)

考虑三分套三分,第一次三分 B 的个数,第二次三分 N 的个数。

感性理解一下,我们最后计算的式子都是类似 |xa| 的形式,是单峰的,所以可以三分,严谨证明的话我也不会,有大佬会的话可以私信联系我。

  • CF1486F

标签:枚举

题目很简单,就是枚举然后分讨计算,但是我一开始想的是枚举交点,比较难写,实际上可以枚举 LCA,然后可以简单计算。

写题之前要想清楚。

  • CF1716E

标签:DP,线段树。

线段树上 DP。

考虑算出所有 2n 次种情况的答案,那么可以在线段树递归上来的时候合并答案。

  • CF1592F1

标签:推性质。

很好的题目。

首先推出操作 2,3 无用,这是简单的(可以用 1 代替),然后发现操作 4 最多用一次,因为还是可以用 1 代替两次操作。

具体的,我们做一个后缀的差分 c[i][j] = a[i][j] ^ a[i + 1][j] ^ a[i][j + 1] ^ a[i + 1][j + 1],实际上面对这种不好处理的区间(矩形)一般都需要转为差分,然后一次 1 操作看作是改变了 cx,y,一次 4 操作是改变了 cx1,y1,cx1,m,cn,y+1,cn,m 四个位置,两次 4 操作会导致 cn,m 不变,可以用 6 次 1 操作代替。

  • CF1592F2

标签:二分图匹配。

延续 F1 的观察,但是现在 4 操作不一定只用一次了。

我们发现如果 cx1,y1,cx1,m,cn,y+1 这些位置不是都有值,那么一定是不优的,因为可以用 1 操作代替。

然后对于这样的位置,我们发现 (x,y) 这个行列只能覆盖一次,那么实际上是一个二分图的形式,可以连边 (x,y)

然后最大匹配就是右下角操作的数量,判断一下 cn,m 的情况即可。

  • CF55D

标签:数位 DP。

【12 / 100】

  • CF1542E

标签:DP。

【11 / 100】

暴力 DP:枚举 LCP,和后面那个的值,额外算一个 DP 数组。

优美的:设 fi,j 表示 1i 的排列对,两个逆序对差为 j 的方案。

大力拆式子,大力前缀和优化即可。

  • CF813F

标签:线段树分治

【11 / 100】

  • CF551E

标签:分块。

【10 / 100】

直接分块,每个块用哈希表记录有哪些出现即可。

  • CF1920F1

标签:图论,搜索

【9 / 100】

直接二分答案,然后 bfs 判断一下就做完了。

Hard Version:

考虑得到每个点到最近的火山的距离,然后建立 Kruskal 重构树,因为要能绕一圈,所以可以随便找一个标准线,要求跨过恰好一次,相当于是每个点拆点,然后答案就是重构树上 LCA。

  • CF1264E

标签:网络流

费用流题。

首先利用竞赛图三元环计数的公式 (n3)i=1n(di2)di 表示出度。

转化为最小化 di(di1)2。这个作为一个边定向的问题,可以用网络流解决,然后在每个点连向终点的时候边权依次为 0,1,,n1,这样可以表示出之前那个式子(等差数列求和),然后直接最小费用最大流。

双倍经验:P4249 [WC2007] 剪刀石头布

  • CF1111D

标签:背包

【8 / 100】

发现这是一个背包问题,我想知道的只是凑出 n2 的体积的方案,然后乘上一个多重集组合数系数即可。

每次直接做是 O(S3n) 的,S 是字符集大小。但是可以退背包,就是原路返回,这样只要预先算一次即可,时间复杂度变成 O(S2n)

  • CF1687C

首先要转化题意,设 s 表示 ab 的前缀和数组。

一次操作要求是 sl1=sr,然后把 s[l,r] 赋值为 sl1,目标是 s 变成全 0

关键点在于你如果不变成 0,操作是无意义的。

然后可以 bfs,把当前 0 的点加入,转移一下,暴力修改的时候使用并查集优化一下即可。

  • CF1325F

标签:dfs 树。

傻了。

第二问很好判断,建出 dfs 树,因为无向图的 dfs 树只有返祖边,那么直接用来判断即可。

若找不到大小至少为根号的环,则一定存在一个大小恰好为根号的独立集,因为对于 dfs 树上的某个点,若其返祖边有 x 条,因为无重边,则环的大小至少为 x+2

若有至少 n2 个返祖边,那么就会出现答案,反之说明至多有 n3 条边,还有至多两条树边,相当于是每个点只能控制 n1 个点,显然会剩下独立集。

  • CF1344C

标签:图论,拓扑排序。

【7 / 100】

傻逼题意,被硬控 2.5h。

注意变量是从小到大钦定的。

那么一个未知数 xi 想要是全称量词,就必须满足其在 DAG 上的前驱后继全都大于 i(这些在其之后被确定)。使用 toposort 实现。

  • CF995F

标签:DP,拉格朗日插值

【13 / 100】

发现答案是一个关于 dn+1 次多项式。

然后树形 DP,做 dn+1 的情况即可。

  • CF1083E The Fair Nut and Rectangles

【14 / 100】
标签 :DP

首先发现 x 递增则 y 递减,然后 DP,转移发现可以斜率优化。

  • CF1000F One Occurrence

【15 / 100】

莫队,值域分块。

  • CF1473E Minimum Path

标签:最短路

【16 / 100】

转化为每次可以边权为 0 或者边权翻倍,发现最优的情况就是题目要求的情况,非法的转移不用管,直接分层图最短路做完了。

  • CF1976F Remove Bridges

标签:贪心。

【17 / 100】

solution

  • CF1082G Petya and Graph

标签:网络流。

【18 / 100】

首先要知道网络流求解最大权闭合子图(闭合子图就是不能有子图内连向外的边)。

设图权为点权和,那么我们这样建模:

S 向 正权点连权值大小的边,负权点向 T 连权值相反数的边,原图的边保留,权值为 inf。

那么考虑这个图的一个割的意义就是选一些不用的正权点权值和减去选一些负权点的权值和。

我们最后求出的最大权闭合子图就是选一些正权点权值和加上选一些负权点的权值和。

两者一加,就是正权点的总和。

对于这个问题,我们把边看作是正权点,点看作是负权的,一条边向两个点连边,直接求解即可。

  • CF1332F Independent Set

标签:树形 DP

????怎么唐成这种题都不会????

发现题目给的联通子图相当于可以断边,那么就设一下 f(i,0/1) 表示 i 选不选,和父亲之间的边选的方案,要断掉的话设一个 g(i) 表示和父亲之间的边不选,i 选不选无所谓的方案,那么直接 DP,g 用一个容斥来减去孤立点的情况。

  • CF1184E2 Daleks' Invasion (medium) & CF1184E3 Daleks' Invasion (hard)

标签:Kruskal 重构树,树链剖分。

【19 / 100】

medium 可以对于最小生成树建重构树,答案就是 LCA 的权值。

hard 要考虑树边,那么把其他边都加入,相当于树上求最小值。

  • CF1188A2 Add on a Tree: Revolution

标签:构造

【20 / 100】

因为边权互不相同,所以有二度点即无解,然后可以直接构造使得每个边能任意加减一个偶数。

  • CF1814D

标签:枚举

如果答案不是 n,就一定有不改变的值,枚举这个,可行的区间只有 O(k) 种,直接暴力 check 是 O(n2k) 的。

发现 f<k 的一定可行,否则最多出现两次,那么直接标记一下前缀和,即可 O(1) check,算答案同理。

  • CF1898F Vova Escapes the Matrix

标签:bfs,次短路。

不会写 BFS 求次短路/kk。想法是对于每个队列中的元素,记录其坐标和来自哪里,以及距离,转移直接打擂台。

  • CF1905E One-X

标签:线段树

【21 / 100】

线段树上同一层的区间长度最多只有两种,长度相同的区间,方案也相同,那么可以对这两种长度分别递推下去。

  • CF498D Traffic Jams in the Land

标签:线段树

一开始还以为是分块简单题,但是发现要记录的是模 LCM 而不是模 al 的值,于是可以直接线段树维护。

  • CF524E Rooks and Rectangles

标签:扫描线,线段树

只能说自己没有什么扫描线思维,bx @喵仔牛奶。

发现了一个矩形是合法的,要么行都被覆盖,要么列都被覆盖,那么分别做即可,可以扫描线加入点,在下边界/右边界出统计答案。

  • CF256E Lucky Arrays

标签:DDP

【22 / 100】

  • CF750E New Year and Old Subsequence

标签:DDP。

【23 / 100】

向量乘矩阵可以 O(n2)

  • CF1731F Function Sum

标签:拉格朗日插值。

【24 / 100】

直接枚举枚举做完了,注意 n 次函数的前缀和是 n+1 次的,要代入 n+2 个点。

  • CF1093E Intersection of Permutations

【25 / 100】

把一个值在两个数组的位置看作是二维平面上的点,每次查询就是矩形内数点。

学习了一下二维分块。

作者:紊莫

出处:https://www.cnblogs.com/wenmoor/p/18271955/note1

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   紊莫  阅读(35)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu