2026-09-29 hetao1733837 的刷题记录

AT_abc477_f ABC477F Count Cells in a Window

原题链接:ABC477F Count Cells in a Window

分析

一眼秒的扫描线......扫描线的本质还是枚举一个,另外一个直接扔到线段树上,当然本题可以写树状数组......

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200005;
int n, m, q;
struct col{
	int id;
	int l, r;
}a[N];
int tot;
struct ask{
	int id, l, r, val;
}b[N << 2];
bool operator < (const ask &tmp1, const ask &tmp2){
	return tmp1.l < tmp2.l;
}
struct BIT{
	int c[N];
	void add(int x, int val){
		for (int i = x; i <= m; i += i & (-i))
			c[i] += val;
	}
	int query(int x){
		int res = 0;
		for (int i = x; i; i -= i & (-i))
			res += c[i];
		return res;
	}
}T1, T2;
void modify(int l, int r, int val){
	T1.add(l, val);
	T1.add(r + 1, -val);
	T2.add(l, val * l);
	T2.add(r + 1, -val * (r + 1));
}
int query(int x){
	return (x + 1) * T1.query(x) - T2.query(x);
}
int ans[N];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> q;
	for (int i = 1; i <= n; i++){
		cin >> a[i].l >> a[i].r;
		a[i].id = i;
	}
	for (int i = 1, A, B, C, D; i <= q; i++){
		cin >> A >> B >> C >> D;
		b[++tot] = {i, B, D, 1};
		b[++tot] = {i, A - 1, D, -1};
		b[++tot] = {i, B, C - 1, -1};
		b[++tot] = {i, A - 1, C - 1, 1};
	}
	sort(b + 1, b + tot + 1);
	int cur = 0;
	for (int i = 1; i <= tot; i++){
		while (cur < b[i].l){
			cur++;
			modify(a[cur].l, a[cur].r, 1);
		}
		if (b[i].r > 0 && b[i].l > 0){
			ans[b[i].id] += b[i].val * query(b[i].r);
		}
	}
	for (int i = 1; i <= q; i++){
		cout << ans[i] << '\n';
	}
} 

AT_arc156_b ARC156B Mex on Blackboard

原题链接:ARC156B Mex on Blackboard

分析

从某些角度而言,我们需要知道 a a a 序列的所有子序列可以组成多少 mex ⁡ \operatorname{mex} mex,假设这个个数是 c n t cnt cnt,那么,答案似乎就是 c n t k cnt^k cntk?

那么,前一个怎么求呢?排序是必要的......然后, a i ≤ 2 × 10 5 a_i\le 2\times 10^5 ai≤2×105,直接遍历似乎就可以了!这么容易?不不不,你会发现,我们每次都会把新的 mex ⁡ \operatorname{mex} mex 加进去。那我似乎可以进行 DP 了?

我们设 d p k k , m e x dp_{kk,mex} dpkk,mex 表示我们现在进行到了第 k k kk kk 轮,这一轮我们要往黑板上写的是 m e x mex mex 的方案数......

转移类似于,从前一个转移,而且,要把这次选满,复杂度估计不低于 O ( n 3 ) O(n^3) O(n3)。

那咋做啊😭


我们发现其实是另外一个分支:

我们发现,如果现在写的是 x x x,且 x x x 是出现过的最大的,那么,我们需要把 0 , x 0,x 0,x 全都写上。假设我们需要 c n t cnt cnt 次才能将其全部写上,那么还剩下 k − c n t k-cnt k−cnt 次。

那么,这个的方案数就是 C k − c n t + x x C_{k-cnt+x}^{x} Ck−cnt+xx。我们枚举值域即可。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
const int N = 1000005;
int n, k, a[N];
int fac[N], inv[N];
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 C(int n, int m){
	if (n < 0 || m < 0 || n < m)
		return 0;
	return fac[n] * inv[n - m] % mod * inv[m] % mod;
}
int vis[N];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> k;
	for (int i = 1; i <= n; i++){
		cin >> a[i];
        vis[a[i]]++;
	}
	fac[0] = 1;
	for (int i = 1; i < N; i++){
		fac[i] = fac[i - 1] * i % mod;
	}
	inv[N - 1] = qpow(fac[N - 1], mod - 2);
	for (int i = N - 2; i >= 0; i--){
		inv[i] = inv[i + 1] * (i + 1) % mod;
	}
	int ans = 0, cnt = 0;
	for (int i = 0; i < N - 5; i++){
		if (!vis[i])
			cnt++;
		if (vis[i + 1])
			continue;
        if (cnt > k) 
            break;
		ans = (ans + C(k - cnt + i, i)) % mod; 
	}
	cout << ans;
}

凭啥这个能过😭

相关推荐
:mnong1 小时前
几何内核“四大金刚“:ACIS、Parasolid、CGM、Open CASCADE 核心特征深度解析
c++·cad·cax
by209991 小时前
从 malloc/free 到 new/delete:真正理解 C++ 中的内存管理与对象生命周期
c语言·c++·经验分享·动态内存管理
欣欣之王来了2 小时前
AI合规专项:AI算法透明度的合规要求
人工智能·算法
wzdark2 小时前
分块思想在算法优化中的实践与应用4
算法
Because_of_Her12 小时前
dfs-洪水填充技巧
笔记·算法·深度优先·洪水填充
m0_380743872 小时前
Qt侧边栏布局的实现示例
开发语言·c++
小静AI工程实验室2 小时前
RSA 算法详解:从模幂原理到 OAEP 加密、PSS 签名与 Python 实验
python·算法
xzal122 小时前
GESP Python笔记
笔记·python·算法
wzdark2 小时前
算法中的记忆化思想与重复子问题优化4
算法