闲话 22.11.5

闲话

调了个多项式板子 跑得飞快
似乎是oi界顶尖科技水平了

所以又发了柚子
srds 一天真的吃不完(
srds “怎么打开?” “树怎么剖的它就怎么剖的”
然后开了(
比较的甜 但是皮是真的不好吃

柚子但不是柚子社呢
下次回去玩一玩柚子社的游戏吧
哪位能给我赞助一份千恋万花(

为啥 lg 上我自己看不到我自己的新头像啊


雨のち曇り晴れ

優しくきっと晴れ

きらきら浮かぶ言葉

もう忘れちゃうけれど

口胡题了(

某些懒得写代码的题
在这一并解决了算了

CF1705E

给定一个长度为 \(n\) 的序列 \(a_1,\cdots,a_n\),你可以每次把两个相等 \(a_i\)\(a_j\) 扔掉,加进来一个 \(a_i+1\)。 给定 \(q\) 次修改,每次将 \(a_k\) 修改为 \(l\),求每次操作后可能出现的最大数。(经过操作后的)

\(1\le n,q,a_i\le 2\times 20^5\)

每个数最后一定出现不超过一次,反之一定不优。
然后考虑一个 01 串,第 \(i\) 位记录 \(i\) 在最终合并完后是否存在。

考虑这个合并等于是在进位。
然后更新就很好更新了。拆成彼此镜像的删除和加入,只讨论加入,删除反转 01 即可。
加入 \(l\) 时找到 \(l\) 后面第一个 0,把这俩之间的所有 1 置零,再把这一位置 1。
询问时输出最高位即可。

线段树即可。但是珂朵莉树的复杂度似乎是更优的。记得推平。
因为是 cf,可以 bitset 用 _Find_next() 卡过去。


CF1634F

对于一个数组 \(X\),有如下操作:对于区间 \([l,r]\),给 \(X_l\) 加上 \(F_1\),给 \(X_{l+1}\) 加上 \(F_2\),以此类推,并且给 \(X_r\) 加上 \(F_{r-l+1}\)。然后将区间 \([l,r]\) 内每个数对 \(MOD\) 取模。\(F\) 数组是这样一个数组:\(F_1=1\)\(F_2=1\),当 \(i>2\)\(F_i=F_{i-1}+F_{i-2}\)

已知两个长度相同的数组 \(A\)\(B\),给出若干次操作,每次操作后你需要求出取模过后的数组 \(A\)\(B\) 是否相等。

\(1\le n,q\le 3\times 10^5, 2 \le MOD \le 10^9 + 7\)

判相等转化成差值为 \(0\)。然后我们只需要维护 \(C_i = A_i - B_i\)。对两个序列的操作可以被转化成对其中一个的操作。
然后考虑在 \(C_i\) 上加入 \(F\) 序列的做法。

如果加入的是递推式确定的值,可以考虑维护与递推式互逆的差分数组使得操作维度减小一维。
在这里考虑维护 \(D_{i} = C_i - C_{i-1} - C_{i-2}\),加和时只需要在 \(D_l\)\(+1\) 即可在后缀上加,在 \(D_{r+1}\)\(-F_{r-l+1}\),在 \(D_{r+2}\)\(-F_{r-l+2}\) 即可抵消。
判断时直接判 \(D\) 是否全 \(0\) 即可。
代码简单。


[NOI2022] 众数

一开始给定 \(n\) 个长度不一的正整数序列,编号为 \(1 \sim n\),初始序列可以为空。这 \(n\) 个序列被视为存在,其他编号对应的序列视为不存在。

\(q\) 次操作,操作有以下类型:

  • \(1 \ x \ y\):在 \(x\) 号序列末尾插入数字 \(y\)。保证 \(x\) 号序列存在,且 \(1 \le x, y \le n + q\)
  • \(2 \ x\):删除 \(x\) 号序列末尾的数字,保证 \(x\) 号序列存在、非空,且 \(1 \le x \le n + q\)
  • \(3 \ m \ x_1 \ x_2 \ x_m\):将 \(x_1, x_2, \ldots, x_m\) 号序列顺次拼接,得到一个新序列,并询问其众数。如果不存在满足上述条件的数,则返回 \(-1\)。数据保证对于任意 \(1 \le i \le m\)\(x_i\) 是一个仍然存在的序列,\(1 \le x_i \le n + q\),且拼接得到的序列非空。注意:不保证 \({x_1, \ldots, x_m}\) 互不相同,询问中的合并操作不会对后续操作产生影响。
  • \(4 \ x_1 \ x_2 \ x_3\):新建一个编号为 \(x_3\) 的序列,其为 \(x_1\) 号序列后顺次添加 \(x_2\) 号序列中数字得到的结果,然后删除 \(x_1, x_2\) 对应的序列。此时序列 \(x_3\) 视为存在,而序列 \(x_1, x_2\) 被视为不存在,在后续操作中也不会被再次使用。保证 \(1 \le x_1, x_2, x_3 \le n + q\)\(x_1 \ne x_2\)、序列 \(x_1, x_2\) 在操作前存在、且在操作前没有序列使用过编号 \(x_3\)

\(1\le n,q\le 5\times 10^5\),输入序列总长度 \(\le 5\times 10^5\),所有 3. 操作中出现的序列个数 \(\le 5\times 10^5\)

受害者发言

image
image
image
image

根据死者的发言,这题的做法是维护摩尔投票合并。

我们直接开 \(n+q\)std::list,每个维护一个序列。
我们直接开 \(n+q\) 棵线段树,每个维护一个序列的元素个数。
线段树上推信息时按摩尔投票法,最后根节点的值就是这个序列中的绝对众数。

    1. 操作直接维护,单次复杂度 \(O(\log n)\)
  1. 操作取得序列根位置的绝对众数,然后在新序列上跑摩尔投票。投出的众数再去原序列里查一遍。因为保证该操作中的序列个数 \(\le 5\times 10^5\),复杂度均摊正确。
  2. 操作启发式合并 std::list 即可。线段树合并的复杂度也是均摊正确。

为什么不用 std::deque 然后启发式合并?
那玩意预留空间太大,会 MLE。

进行了一波 k 叉分治 fft 的实现

code
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (register int i = (a), i##_ = (b) + 1; i < i##_; ++i)
#define pre(i,a,b) for (register int i = (a), i##_ = (b) - 1; i > i##_; --i)
const int N = 3e5 + 10, mod = 998244353, inv2 = (mod + 1) >> 1, g = 3, B = 5; 
using ull = unsigned long long;
using poly = vector<int> ;
int n;
int limit, trs[N], w[N], lgv[N], inv[N];
poly F, G;

int qp(int a, int b) { int ret = 1;  while (b) { if (b & 1) ret = 1ll * ret * a % mod; a = 1ll * a * a % mod; b >>= 1; } return ret; }
void init(int n) {
    limit = 1; while (limit < n) limit <<= 1;
	inv[0] = inv[1] = 1;
    for (int i = 1; i < limit; ++ i) trs[i] = (trs[i >> 1] >> 1) | (( i & 1 ) ? limit >> 1 : 0);
    for (int i = 1; i < limit; i <<= 1) {
        w[i] = 1; int w0 = qp(g, (mod - 1) / (i << 1));
        rep(j,1,i-1) w[i + j] = 1ll * w[i + j - 1] * w0 % mod;
    } rep(i,2,limit) lgv[i] = lgv[i >> 1] + 1, inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
}

void DFT(poly & A, int len) {
    int t = lgv[limit / len]; static ull tmp[N];
    rep(i,0,len-1) tmp[trs[i] >> t] = A[i];
    for (int i = 1; i < len; i <<= 1) for (int j = 0; j < len; j += i << 1) for (int k = 0; k < i; ++ k) {
        int v = 1ll * tmp[i + j + k] * w[i + k] % mod;
        tmp[i + j + k] = tmp[j + k] + mod - v; tmp[j + k] += v;
    } for (int i = 0; i < len; ++ i) A[i] = tmp[i] % mod;
}
void IDFT(poly & A, int len) {
    reverse(A.begin()+1, A.begin()+len); DFT(A, len);
    int iv = mod - (mod - 1) / len;
    for (int i = 0; i < len; ++ i) A[i] = 1ll * A[i] * iv % mod;
}

poly _f[20][1 << B], _g[20][1 << B];
void dac_FFT(poly & F, const poly & G, int l, int r, int dep, void plain(poly&,const poly&,int,int)) {
    if (r - l + 1 <= 128) { plain(F, G, l, r); return; }
    static poly tmp; tmp.resize(0), tmp.resize(N);
    int d = 1 << ((dep - 1) * B);
    for (int i = 0; ; ++ i) {
        int L = l + i * d, R = min(r, L + d - 1);
        if (i) {
			// memset(tmp.begin(), 0, (d << 3));
            fill(tmp.begin(), tmp.begin() + (d << 1), 0);
            for (int j = 0; j < i; ++ j) for (int k = 0; k < (d << 1); ++ k) 
                tmp[k] = (tmp[k] + 1ll * _f[dep][j][k] * _g[dep][i-j][k]) % mod;
            IDFT(tmp, d << 1);
            rep(j,L,R) F[j] = (F[j] + tmp[j - L + d]) % mod;
        }
        dac_FFT(F, G, L, R, dep - 1, plain);
        if (R == r) return;
		// memset(_f[dep][i].begin(), 0, (d << 3));
        fill(_f[dep][i].begin(), _f[dep][i].begin() + (d << 1), 0);
        copy(F.begin()+L, F.begin()+R+1, _f[dep][i].begin());
        DFT(_f[dep][i], d << 1);
    }
}

void dac(poly & F, const poly & G, int n, void plain(poly&,const poly&,int,int)) {
	// memset(F.begin(), 0, (n << 2));
    fill(F.begin(), F.begin()+n, 0);
    if (n <= 128) { plain(F, G, 0, n-1); return; }
    int len = 1, dep = 0; 
    while (len < n) len <<= B, dep ++; len >>= B;
    rep(i,1,dep) {
        int d = 1 << ((i-1) * B), tn = min((1 << B) - 1, (n - 1) / d);
        rep(j,1,tn) {
            int L = (j - 1) * d + 1, R = min(n - 1, (j + 1) * d - 1);
            _f[i][j-1].resize(d << 1);
            _g[i][j].resize(d << 1);
			// memset(_g[i][j].begin(), 0, (d << 3));
            fill(_g[i][j].begin(), _g[i][j].begin() + (d << 1), 0);
            copy(G.begin()+L, G.begin()+R+1, _g[i][j].begin() + 1);
            DFT(_g[i][j], d << 1);
        } 
    } 
    dac_FFT(F, G, 0, n-1, dep, plain);
}

void plain_inv(poly & F, const poly & G, int l, int r) {
    if (!l) F[l] = 1;
    rep(i,l+1,r) rep(j,l,i-1) F[i] = (F[i] + 1ll * F[j] * G[i - j]) % mod;
}
void plain_ln(poly & F, const poly & G, int l, int r) {
	if (!l) F[l] = 0; else F[l] = (1ll * l * G[l] - F[l] + mod) % mod;
	rep(i,l+1,r) {
		rep(j,l,i-1) F[i] = (F[i] + 1ll * F[j] * G[i - j]) % mod;
		F[i] = (1ll * i * G[i] - F[i] + mod) % mod;
	}
}
void plain_exp(poly & F, const poly & G, int l, int r) {
	if (!l) F[l] = 1; else F[l] = 1ll * F[l] * inv[l] % mod;
	rep(i,l+1,r) {
		rep(j,l,i-1) F[i] = (F[i] + 1ll * F[j] * G[i - j]) % mod;
		F[i] = 1ll * F[i] * inv[i] % mod;
	}
}

void Ln(poly & Ret, const poly & Inp, const int & n) {
	dac(Ret, Inp, n, plain_ln);
	Ret[0] = 0; rep(i,1,n-1) Ret[i] = 1ll * Ret[i] * inv[i] % mod;
}
void Exp(poly & Ret, const poly & Inp, const int & n) {
	static poly _G; _G.resize(n);
	rep(i,0,n-1) _G[i] = 1ll * i * G[i] % mod;
    dac(F, _G, n, plain_exp);
}
void Inv(poly & Ret, const poly & Inp, const int & n) {
	static poly _G; _G.resize(n);
	int ivp = qp(G[0], mod - 2);
	rep(i,0,n-1) _G[i] = 1ll * (mod - G[i]) * ivp % mod;
	dac(Ret, _G, n, plain_inv);
	rep(i,0,n-1) F[i] = 1ll * F[i] * ivp % mod;
}
void Pow(poly & Ret, const poly & Inp, const int & C, const int & n) {
	static poly _R; _R.resize(0), _R.resize(n);
	Ln(_R, Inp, n);
	for (int i = 0; i < n; ++ i) _R[i] = 1ll * _R[i] * C % mod;
	Exp(Ret, _R, n);
}

signed main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n; init(n); F.resize(n), G.resize(n);
    for (int i = 0; i < n; ++ i) cin >> G[i];
    Exp(F, G, n);
    for (int i = 0; i < n; ++ i) cout << F[i] << ' ';
}
posted @ 2022-11-05 20:50  joke3579  阅读(88)  评论(8编辑  收藏  举报