|
|
# T5 数据结构题 题解 我们将询问转化为如下问题 定义 $f(l,r)$ $(l \le r)$ 如下: 当 $l=r$ 时,$f(l,r)=a_l$;否则,$f(l,r)=a_l^{f(l+1,r)}$ 每次操作 $2$,输出 $f(l,r)\bmod p$ 那我们该如何维护呢? 这里我们需要一个前置知识,叫做扩展欧拉定理,即: $$a^b\equiv \begin{cases}a^{b \bmod \varphi(p)}(b<\varphi(p))\\a^{b \bmod \varphi(p)+\varphi(p)}(b\ge\varphi(p))\end{cases}\pmod p$$ 那么 $$f(l,r)\equiv a^{f(l+1,r)\bmod \varphi(p)+[b\ge \varphi(p)]\times \varphi(p)}\pmod p$$ 那么,求解 $f(l,r)\bmod p$ 就变成了求解 $f(l+1,r)\bmod \varphi(p)$,并判断 $f(l+1,r)$ 与 $p$ 的关系 然后我们就可以递归求解了 递归边界的话,则有三个 当 $l=r$ 时,$f(l,r)\bmod p\equiv a_l\pmod p$ 当 $p=1$ 时,$f(l,r)\bmod p\equiv 0\pmod p$ 当 $a_l=1$ 时,$f(l,r)\bmod p\equiv 1\pmod p$ 那么这个递归的复杂度是多少呢? 我们分析一下将 $\varphi(p)\to p$ 直到 $p=1$ 的时间复杂度是多少 由 $\varphi(p)=p\prod_{i=1}^{n} \frac{p_i-1}{p_i}$ $(p=\prod_{i=1}^{n}{p_i}^{k_i})$可知 当 $p$ 为偶数时,上述式子必有一项是 $\frac{1}{2}$,所以 $\varphi(p)\le\frac{1}{2}p$ 当 $p$ 为奇数时,上述式子的 $p_i-1$ 必是偶数,因此 $\varphi(p)$ 为偶数,回到 $p$ 为偶数的情况 因此最多经过 $O(logn)$ 次递归就可以得出答案 至于判断 $f(l+1,r)$ 与 $p$ 的关系,可以让递归函数返回一个结构体,结构体第一项存 $f(l+1,r)\bmod \varphi(p)$ 的值,第二项存 $f(l+1,r)$ 与 $\varphi(p)$ 的大小关系,前者大于等于后者,这一项就是 $1$,反之则为 $0$ 区间和我们用树状数组维护差分即可 时间复杂度:$O(mlogqlogn)$
题目4318 数据结构题
AAAAAAAAAA
3
评论
2026-02-28 13:04:35
|
|
|
题目4323 十二重计数法(第一关)
AAAAA
5
评论
2026-02-27 20:33:10
|
|
|
题目4324 十二重计数法(第二关)
AAAAA
5
评论
2026-02-27 20:32:11
|
|
|
f[i][j]统一定义为i个小球放到j个盒子里的方案数 1.m^n 2.m!/(m-n)! 3.f[i][j]=j*f[i-1][j]+(m-j+1)*f[i-1][j-1] 考虑容斥可以O(n) 4.第二类斯特林数S[n][1]+...+S[n][m] O(n^2)直接递推S[i][j]=S[i-1][j-1]+j*S[i-1][j] O(nlogn)NTT,斯特林数反演 5.[n<=m] 6.S[n][m] 7.C(n+m-1,m-1) 8.C(m,n) 9.C(n-1,m-1) 10.f[i][j]=f[i][j-1]+f[i-j][j] 考虑球的数量>=根号n的盒子的个数<=根号n个可以分块O(n^1.5) 五边形数定理可优化到O(nlogn) 11.[n<=m] 12.f[i][j]=f[i-1][j-1]+f[i-j][j] 自然数拆分 同10
题目4323 十二重计数法(第一关)
1
评论
2026-02-27 15:23:31
|
|
|
更好的阅读体验:https://www.cnblogs.com/To-Carpe-Diem/p/19645638 更好的阅读体验(加强版):https://www.cnblogs.com/To-Carpe-Diem/p/19645952 $\newcommand{\binom}[2]{{#1 \choose #2}}$ 大意 $n$ 对情侣,恰好 $k$ 对在 $2 \times n$ 的电影院中坐一起的方案数。
思路 很好的题目,使得我的大脑旋转。 首先我们先定义函数 $f(n, k)$ 表示 $n$ 对情侣有 $k$ 对恰好坐到一块的方案数。首先我们要从 $n$ 对情侣中选择 $k$ 对,这个是 $\binom{n}{k}$ 的,再从 $n$ 排选择 $k$ 排,这个也是 $\binom{n}{k}$ 的,考虑到这 $k$ 对情侣间也有先后顺序,贡献就是 $k!$,两人可以换位,贡献是 $2 ^ k$,剩下有 $n - k$ 对情侣,我们只需要将其错排即可。 定义 $g(m)$ 表示 $m$ 对情侣错排的方案数,我们考虑这个怎么求。这个我们可以利用容斥原理,我们考虑直接计算至少 $j$ 对和睦的方案数,那么这个的贡献与上面的类似,应当是 $\binom{m}{j} ^ 2 j! 2 ^ j (2(m - j))!$,那么由容斥可知:$g(m) = \sum_{j = 0} ^ {m}(-1) ^ j \binom{m}{j} ^ 2 j! 2 ^ j (2(m - j))!$ 那么我们合并一下整个式子,就是:$f(n, k) = \binom{n}{k} ^ 2 k ! 2 ^ k g(n - k) = \binom{n}{k} ^ 2 k ! 2 ^ k \sum_{j = 0} ^ {n - k}(-1) ^ j \binom{n - k}{j} ^ 2 j! 2 ^ j (2(n - k - j))!$ 这个式子我们是可以直接求的,于是就完成了。 接下来进入正题,我们注意到刚刚的弱化版内的 $f(n, k) = \binom{n}{k} ^ 2 k ! 2 ^ k D(n - k) $,且 $D(n) = \sum_{i = 0} ^ {n} (-1) ^ i\binom{n}{i} ^ 2 i! 2 ^ i (2(n - i))!$,我们考虑对于 $D(n)$ 进行化简. $\sum_{i = 0} ^ {n}(-1) \binom{n}{i} ^ 2 i! 2 ^ i (2(n - i)) != (n!) ^ 2 \sum_{i = 0} ^ n \frac{(2(n - i))!}{(n - i)! ^ 2} \frac{(-2) ^ i}{i!}$ 这里我们就可以直接做卷积了,但是问题在于这个题目要求的复杂度太过苛刻,卷积无法通过此题,我们考虑构造生成函数。 我们设:$F(x) = (n!) ^ 2 \sum_{i = 0} ^ n \frac{(2(n - i))!}{(n - i)! ^ 2} \frac{(-2) ^ i}{i!} x^i,G[n] = \frac{(2n)!}{n!^2},P[n] = \frac{(-2) ^ i}{n !}$。那么,由离散卷积可知:$F(x) = G(x) * P(x)$ 接下来,我们只需要分别对于 $G(x)$ 和 $P(x)$ 化简即可。首先,对于 $G(x)$ 来说,我们可以利用**广义二项式定理**,那么什么是广义二项式定理呢?对于任意实数 $\alpha$,都有 $(1 + z) ^ \alpha = \sum_{i = 0} ^ {\infty} \binom{\alpha}{i} z ^ i$,那么说我们就可以化简 $G(x)$ 了:$G(x) = \sum_{i = 0} \frac{(-2x) ^ i}{i!} x ^ i = \sum_{i = 0} \binom{2i}{i}x^i = \frac{1}{\sqrt{1 - 4x}}$对于 $P(x)$ 来说,直接化简:$P(x) = \sum_{i = 0} \frac{(-2x)!}{i!} = e ^ {-2x}$ 经过化简,我们可以最终得到:$F(x) = \frac{e ^ {-2x}}{\sqrt{1 - 4x}}$对于这个生成函数,为了得到与自身相关的式子进行递推,我们选择对其求导。$F'(x) = \frac{8x * e ^ {-2x}}{(1 - 4x) ^ \frac{3}{2}} = \frac{8x}{1 - 4x} F(x)$整理一下:$F'(x) = 4xF'(x) + 8xF(x)$。提取 $[x ^ n]$ 的系数:$F'[n] = 4xF'[n - 1] + 8xF[n - 1]$。稍施小计,我们可以直接得到关于 $F[n]$ 的递推式:$(n + 1)F[n + 1] = 4nF[n] + 8F[n - 1]$ 你可能以为万事大吉了,但是问题是我们还有个 $(n!) ^ 2$ 的系数在最开始被我们提出去了,我们要把这玩意弄回来,带入 $F[n] = \frac{D(n)}{n!} ^ 2$:$(n + 1)\frac{D[n + 1]}{(n + 1)!} = 4n \frac{D[n]}{n!^2} + 8 \frac{D[n - 1]}{(n - 1)! ^ 2}$我们就可以得到关于 $D[n]$ 的递推式:$D[n + 1] = 4n(n + 1)D[n] + 8n ^ 2(n + 1)D[n - 1]$ 直接 $O(n)$ 递推即可。
代码
#include<iostream>
using namespace std;
#define int long long
const int MOD = 998244353;
const int MAXN = 2e3 + 5;
int C[MAXN][MAXN];
int fac[MAXN];
int g[MAXN], pow2[MAXN];
void init(){
C[0][0] = 1;
for(int i = 1;i < MAXN;i ++){
C[i][0] = C[i][i] = 1;
for(int j = 1;j < i;j ++){
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
}
}
fac[0] = 1;
for(int i = 1;i < MAXN;i ++){
fac[i] = (fac[i - 1] * i) % MOD;
}
pow2[0] = 1;
for(int i = 1;i < MAXN;i ++){
pow2[i] = pow2[i - 1] * 2 % MOD;
}
for(int m = 0;m <= 1000;m ++){
g[m] = 0;
for(int j = 0;j <= m;j ++){
int a = (j % 2 == 0) ? 1 : MOD - 1;
int res = C[m][j] * C[m][j] % MOD;
res = (res * fac[j]) % MOD;
res = (res * pow2[j]) % MOD;
res = (res * fac[2 * (m - j)]) % MOD;
res = (res * a) % MOD;
g[m] = (g[m] + res) % MOD;
}
}
return;
}
int f(int n, int k){
int res = (C[n][k] * C[n][k]) % MOD;
res = (res * fac[k]) % MOD;
res = (res * pow2[k]) % MOD;
res = (res * g[n - k]) % MOD;
return res;
}
int T, n, k;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
init();
cin >> T;
while(T --){
cin >> n;
for(int i = 0;i <= n;i ++){
cout << f(n, i) << '\n';
}
}
return 0;
}
题目3353 情侣?给我烧了
A
5
评论
2026-02-27 11:52:19
|
|
|
更好的阅读体验:https://www.cnblogs.com/To-Carpe-Diem/p/19617614
大意 每一个小朋友在得到自己喜欢的饮料和食物的时候,就实现了其愿望,问最多能实现多少奶牛的愿望。
思路 首先我们考虑这样的三元关系 $(饮料,小朋友,食物)$,这样的三元关系,如果我们直接在中间连边去跑最大流是否有问题呢? 显然是有问题的,如下图:
这样我们发现个奇怪的问题,一个小朋友对应的喜欢的食物和饮料其实是很多的,但是这样会使得不同的饮料与食物都对一个小朋友产生影响,现在我们需要做的是给一个点上约束,而这种技巧叫做拆点。 我们考虑将每个小朋友拆为 $in$ 和 $out$,在 $in$ 和 $out$ 间连容量为 $1$ 的边,这样我们就可以保证每个小朋友只被算一次,如下图:
在拆完点之后直接跑最大流即可。
代码
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX_N = 1000;
const int MAX_M = 100000;
struct edge {
int v, c, next;
} e[MAX_M];
int p[MAX_N], eid;
void init() {
memset(p, -1, sizeof(p));
eid = 0;
}
void insert(int u, int v, int c) {
e[eid].v = v;
e[eid].next = p[u];
e[eid].c = c;
p[u] = eid++;
}
void addedge(int u, int v, int c) {
insert(u, v, c);
insert(v, u, 0);
}
int S, T;
int d[MAX_N];
bool bfs() {
memset(d, -1, sizeof(d));
queue<int> q;
q.push(S);
d[S] = 0;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = p[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if (e[i].c > 0 && d[v] == -1) {
q.push(v);
d[v] = d[u] + 1;
}
}
}
return (d[T] != -1);
}
int dfs(int u, int flow) {
if (u == T) {
return flow;
}
int res = 0;
for (int i = p[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if (e[i].c > 0 && d[u] + 1 == d[v]) {
int tmp = dfs(v, min(flow, e[i].c));
flow -= tmp;
e[i].c -= tmp;
res += tmp;
e[i ^ 1].c += tmp;
if (flow == 0) {
break;
}
}
}
if (res == 0) {
d[u] = -1;
}
return res;
}
int Dinic() {
int res = 0;
while (bfs()) {
res += dfs(S, INF);
}
return res;
}
int main() {
init();
int n, m, k;
cin >> n >> m >> k;
for(int i = 1;i <= n;i ++){
addedge(m + i, m + n + i, 1);
int a, b; cin >> a >> b;
for(int j = 0;j < a;j ++){
int x; cin >> x;
addedge(x, m + i, 1);
}
for(int j = 0;j < b;j ++){
int x; cin >> x;
addedge(m + n + i, m + 2 * n + x, 1);
}
}
S = 0; T = m + 2 * n + k + 1;
for(int i = 1;i <= m;i ++){
addedge(S, i, 1);
}
for(int i = 1;i <= k;i ++){
addedge(m + 2 * n + i, T, 1);
}
cout << Dinic() << endl;
return 0;
}
题目2727 [USACO Open07]牛的进餐
7
2 条 评论
2026-02-26 12:01:19
|