闲话 22.10.3

闲话

最近有一件事我比较在意。

某一日 EI 发了一个犇犇

众所周知,这是《四重罪孽》里的一句歌词

然后某些中V厨就按耐不住自己手头的歌词了
image
image

回想初二在家的那段时间
一套作业
带上耳机循环一天《妄想症》
的时光

让我现在还能唱一点四重罪孽

但是现在早就不记得词曲了 下次回家听听吧


夢の続きを知りたいのかい?

誰も見たこと無い絵本を

捲りなさい

それがあなたの

望む世界だとしよう

夢の終わりで眠ればいい

杂题

CF1605F

称一个长度为 \(n\) 的序列 \(a\)\(\text{PalindORme}\) 的,当且仅当对于任意 \(1 \le i \le n\),满足 \(a_1 | a_2 | \dots | a_i = a_n | a_{n-1} | \dots |a_{n-i+1}\),其中 | 表示按位或运算。称一个长度为 \(n\) 的序列 \(b\)\(\text{good}\) 的,当且仅当它可以重排成一个 \(\text{PalindORme}\) 的序列。

给你 \(n,k,m\),求长度为 \(n\),每个元素值域为 \([0,2^k)\) 的序列中有多少个是 \(\text{good}\) 的,对 \(m\) 取模。

\(n,k\le 80\)

读题。读完了可以发现合法序列是关于中心对称的。具体地,从两边开始分别向中间镜像地拓展一个数,每次加入的二进制位是相同的。
然后刻画一下这个性质:
首先整一个计数器 \(V = 0\)。每次选择这个序列两端的数 \(x,y\),一定满足 \(x | V = y | V\)。赋 \(V \leftarrow x|V\),再把这两个数从序列中删除。

由于需要计数的串是重排之后的,因此对于 \(\text{good}\) 的序列,可以通过若干次操作变为长度不超过 1 的序列:
仍然是初始为 0 的计数器,每次选择一对任意位置的数 \(x,y\) 满足 \(x | V = y | V\),赋 \(V \leftarrow x|V\),随后把这两个数删除。

对于不 \(\text{good}\) 的序列,定义它的最优子序列为通过上述操作移除的序列。可以发现在移除最优子序列后,不 \(\text{good}\) 的序列剩余元素都满足 xor \(V\) 不为 0 且之间两两不同。
因此一个不 \(\text{good}\) 的序列能够生成一个长度小于它的 \(\text{good}\) 的序列。

考虑一个套路容斥。
\(f_{i,j}\) 表示长度为 \(i\),二进制位数量为 \(j\) 的序列数,\(g_{i,j}\) 表示长度为 \(i\),二进制位数量为 \(j\) 的不合法序列数,\(h_{i,j}\) 表示长度为 \(i\),二进制位数量为 \(j\) ,内部元素均不为 0 且两两不同的序列数。

由定义,可以得到 \(f_{i,j}\) 的计算方式:

\[f_{i,j} = \sum_{k=0}^j (-1)^{j-k} \binom{j}{k} (2^k)^i \]

\(h_{i,j}\) 的计算式也可类似地得到:

\[h_{i,j} = \sum_{k=0}^j (-1)^{j-k} \binom{j}{k} (2^k-1)^{\underline i} \]

然后可以枚举最优子序列长度和二进制位个数来得到 \(g_{i,j}\)

\[g_{i,j} = \sum_{x=1}^i\sum_{y=1}^j \binom{i}{x} \binom{j}{y} (2^y)^{i-x} \times h_{i-x,j-y}\times (f_{x,y} - g_{x,y}) \]

意义:我们首先钦定最优子序列的长度 \(x\) 和位数 \(y\),这部分的总种类数是 \(\binom{i}{x} \binom{j}{y}\) 的。对于长度为 \((i-x)\) 的每个剩余元素,能任意填入最优子序列中已经存在的 \(y\) 位,这部分的总种类数是 \((2^y)^{i-x}\) 的。由于剩余元素都满足 xor \(V\) 不为 0 且之间两两不同,这部分的种类数是 \(h_{i-x,j-y}\) 的。最后考虑最优子序列的种类数,为 \((f_{x,y} - g_{x,y})\)。求积再求和即为上式。

然后递推就完了。
总时间复杂度 \(O(n^2k^2)\)

code
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (register int (i) = (a); (i) <= (b); ++(i))
#define pre(i,a,b) for (register int (i) = (a); (i) >= (b); --(i))
const int N = 90 + 10;
int n, k, mod, pw[N * N], C[N][N], f[N][N], g[N][N], h[N][N], ans;

typedef long long ll; typedef __int128 lll;
struct FastMod { int m; ll b; void init(int _m) { m = _m; b = ((lll)1<<64) / m; } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod;
int add(int a, int b) { return (a += b) >= mod ? a - mod : a; }
int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }

int L(int n, int m) { int ret = 1; rep(i,0,m-1) ret = mul(ret, n - i + mod); return ret; }

void init(int bnd) {
    Mod.init(mod);
    rep(i,0,bnd) C[i][0] = 1;
    pw[0] = 1;
    rep(i,1,bnd) {
        rep(j,1,i) C[i][j] = add(C[i-1][j-1], C[i-1][j]);
    } 
    rep(i,1,n*k) pw[i] = add(pw[i-1], pw[i-1]); 
}   

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> k >> mod;
    init(max(n, k));
    rep(i,0,n) rep(j,0,k) rep(l,0,j) {
        f[i][j] = add(f[i][j], mul(((j - l) & 1) ? mod - C[j][l] : C[j][l], pw[l * i]));
        h[i][j] = add(h[i][j], mul(((j - l) & 1) ? mod - C[j][l] : C[j][l], L(pw[l] - 1, i)));
    }
    rep(i,1,n) rep(j,1,k) rep(i2,0,i-1) rep(j2,0,j-1) 
        if ((n & 1) and (i == n) and (i2 == n-1)) continue;
        else g[i][j] = add(g[i][j], mul(C[i][i2], C[j][j2], pw[j2 * (i - i2)], h[i - i2][j - j2], f[i2][j2] + mod - g[i2][j2]));
    rep(i,0,k) ans = add(ans, mul(C[k][i], f[n][i] + mod - g[n][i]));
    cout << ans << endl;
}
posted @ 2022-10-03 16:32  joke3579  阅读(88)  评论(5编辑  收藏  举报