CF1151F Sonya and Informatics
给一个长度为 的 串,进行 次操作,每次操作选择两个位置 ,交换 上的数,求 次操作后,该 串变成非降序列的概率,答案对 取模。
sol
好题,概率 dp
。
设有 个 ,那么题意就是让 均为 , 均为 。
令 表示 个操作后,前 个数中有 个 的方案数,答案即为 ,边界:, 为原序列前 个数中 的个数。
对于 ,考虑它是如何转移来的:
- 之前有 个 ,第 次交换换来一个 ,由于前面 的个数与后面 的个数均为 ,顾方案数为 。
- 之前有 个 ,第 次交换换走一个 ,由于前面有 个 ,后面有 个 ,顾方案数为 。
- 之前本来就有 个 ,第 次操作没换走也没换来,四种情况:前面交换,后面交换,前后交换 ,前后交换 ,则方案数为 。
到这里差点结束了,总结:。
考虑到 ,经验告诉我们直接上矩阵快速幂,毕竟这转移无需判断。
其中 ,,。
时间复杂度 。
#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x * f;
}
const int _ = 107, p = 1e9 + 7;
int n, k, m, t, Ans, A[_], a[_], b[_], c[_];
struct matrix {
int a[_][_];
void init() {
memset(a, 0, sizeof a);
}
matrix mul(matrix x) {
matrix res;
res.init();
for (int i = 0; i <= m; ++i)
for (int j = 0; j <= m; ++j)
for (int k = 0; k <= m; ++k)
res.a[i][j] = (res.a[i][j] + a[i][k] * x.a[k][j] % p) % p;
return res;
}
} ans, base;
void Qpow(int k) {
while (k) {
if (k & 1)
ans = ans.mul(base);
k >>= 1, base = base.mul(base);
}
}
inline int qpow(int x, int y) {
int res = 1;
while (y) {
if (y & 1)
res = res * x % p;
y >>= 1, x = x * x % p;
}
return res;
}
signed main() {
n = read(), k = read();
for (int i = 1; i <= n; ++i) A[i] = read();
for (int i = 1; i <= n; ++i) m += (A[i] == 0);
for (int i = 1; i <= m; ++i) t += (A[i] == 0);
for (int i = 0; i <= m; ++i) {
a[i] = (m - i) * (m - i) % p;
b[i] = i * (n - 2 * m + i) % p;
c[i] = (m * (m - 1) * qpow(2, p - 2) % p + (n - m) * (n - m - 1) * qpow(2, p - 2) % p + (m - i) * (n - 2 * m + 2 * i) % p) % p;
}
ans.init();
for (int i = 0; i <= m; ++i) ans.a[i][i] = 1;
base.init();
base.a[0][0] = c[0], base.a[0][1] = b[1];
base.a[m][m - 1] = a[m - 1], base.a[m][m] = c[m];
for (int i = 1; i <= m - 1; ++i) {
base.a[i][i - 1] = a[i - 1];
base.a[i][i] = c[i];
base.a[i][i + 1] = b[i + 1];
}
Qpow(k);
base.init();
base.a[t][0] = 1;
ans = ans.mul(base);
for (int i = 0; i <= m; ++i)
Ans = (Ans + ans.a[i][0]) % p;
printf("%lld", ans.a[m][0] * qpow(Ans, p - 2) % p);
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122014
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通