HDU - 7315 Data Generation( 2023“钉耙编程”中国大学生算法设计超级联赛第四场 D)

4 篇文章 0 订阅
文章讨论了Yoshinow2001为生成随机排列所使用的算法,以及他对算法随机性的担忧。通过期望DP的方法,建立了交换次数与元素不在原位概率的关系,并用矩阵运算求解了答案的数学期望。代码示例展示了如何实现这一计算过程。
摘要由CSDN通过智能技术生成

题目大意

Yoshinow2001 \text{Yoshinow2001} Yoshinow2001 正在为他的问题生成数据。他想要生成 { 0 , … , n − 1 } \{0,…,n−1\} {0,,n1} 的一个随机排列,因此他使用了以下算法:

在这里插入图片描述

在这里,我们可以假设函数 rand ⁡ ( )   m o d   n \operatorname{rand}() \bmod n rand()modn 能够以等概率地在集合 { 0 , . . . , n − 1 } \{0,...,n-1\} {0,...,n1} 中生成随机整数。

现在 Yoshinow2001 \text{Yoshinow2001} Yoshinow2001 担心这个算法不够随机。毕竟,如果要随机排列一个序列,使得 a i ≠ i a_i≠i ai=i 的元素数量的期望应该是 n − 1 n-1 n1。所以他想询问最终答案 a n s ans ans 的数学期望是多少。

思路

期望DP。

我们设 f i f_i fi 表示 i i i 次交换后当前值在原位的概率, g i g_i gi 表示 i i i 次交换后当前值不在原位的概率。

于是乎我们容易推出以下式子:

f i = g i − 1 ⋅ 2 n 2 + f i − 1 ⋅ ( n − 1 ) 2 n 2 g i = g i − 1 ⋅ n 2 − 2 n 2 + f i − 1 ⋅ 2 n − 2 n f_i=g_{i-1}\cdot \dfrac{2}{n^2}+f_{i-1}\cdot \dfrac{(n-1)^2}{n^2}\\ \\ \qquad \\ g_i=g_{i-1}\cdot \dfrac{n^2-2}{n^2}+f_{i-1}\cdot \dfrac{2n-2}{n} fi=gi1n22+fi1n2(n1)2gi=gi1n2n22+fi1n2n2

于是乎把这个式子往上怼就可以了。(拿下)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 998244353;
LL n, m;
struct matrix {
    LL a[2][2];
    matrix operator* (const matrix &x) const {
        matrix ans;
        ans.a[0][0] = (a[0][0] * x.a[0][0] + a[0][1] * x.a[1][0]) % mod;
        ans.a[0][1] = (a[0][0] * x.a[0][1] + a[0][1] * x.a[1][1]) % mod;
        ans.a[1][0] = (a[1][0] * x.a[0][0] + a[1][1] * x.a[1][0]) % mod;
        ans.a[1][1] = (a[1][0] * x.a[0][1] + a[1][1] * x.a[1][1]) % mod;
        return ans;
    }
};
LL ksm(LL a, LL b) {
    LL ans = 1;
    while (b) {
        if (b & 1) ans = ans * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return ans;
}
matrix ksm(matrix a, LL b) {
    matrix ans = a;
    b--;
    while (b) {
        if (b & 1) ans = ans * a;
        a = a * a;
        b >>= 1;
    }
    return ans;
}
int main() {
    int t;
    cin >> t;
    while (t--) {
        scanf("%lld%lld", &n, &m);
        n %= mod;
        LL invsqrn = ksm(n * n % mod, mod - 2);
        matrix aa;
        aa.a[0][0] = ((n * n - 2 * n + 2) % mod * invsqrn % mod + mod) % mod;
        aa.a[0][1] = (1 - aa.a[0][0] + mod)%mod;
        aa.a[1][0] = 2 * invsqrn % mod;
        aa.a[1][1] = (1 - aa.a[1][0] + mod) % mod;
        if (m) aa = ksm(aa, m);
        printf("%lld\n", aa.a[0][1] * n % mod);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值