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;
}
凭啥这个能过😭