首页 > 其他分享 >Codeforces Round #829 (Div. 2) E // 概率dp

Codeforces Round #829 (Div. 2) E // 概率dp

时间:2022-10-24 12:55:50浏览次数:72  
标签:count cnt le int Codeforces 829 数组 Div

题目来源:Codeforces Round #829 (Div. 2) E - Wish I Knew How to Sort

题目链接:Problem - E - Codeforces


题意

给定大小为 \(n\) 的仅包含 \(0\)、\(1\) 的数组 \(a\),每次操作可以随机地选择两个下标 \(i,j\)(\(1 \le i < j \le n\)),若有 \(a_i > a_j\),则交换 \(a_i\) 和 \(a_j\) 。

问:将整个数组从小到大排序所需要的操作次数的期望。

数据范围:\(1 \le n \le 2·10^5,1 \le \sum{n} \le 2·10^5\).

思路:概率dp

记数组中 \(0\) 的数量为 \(cnt_0\),\(1\) 的数量为 \(cnt_1\),则排序后的数组应该是 \(cnt_0\) 个 \(0\),再有 \(cnt_1\) 个 \(1\)。

因此,在原数组中,位置在 \([1,cnt_0]\) 的 \(1\) 是需要交换的,记其数量为 \(count\),位置在 \([cnt_0 + 1, n]\) 的 \(0\) 也是需要交换的,且数量等于 \(count\)。若一次操作,选中的下标 \(i,j\),满足 \(1 \le i \le cnt_0\) 且 \(a_i = 1\),\(cnt_0 + 1 \le j \le n\) 且 \(a_j = 0\),则这次操作可以让 \(count\) 减小\(1\)。

记 \(f_i\) 为 当前需要交换的 \(0\)、\(1\) 等于 \(i\) 时,将数组从小到大排序还需要的操作次数的期望。此时进行一次成功操作的可能是:先取出一个需要交换的 \(0\) 的下标,再取出一个需要交换的 \(1\) 的下标,或者反过来。于是 \(f_i\) 转移到 \(f_{i-1}\) 的概率 \(p_i\) 为:\(\large \frac{2·i^2}{n·(n-1)}\),即有 \(f_i = f_{i - 1} + {\large \frac{1}{p_i}} = f_{i - 1} + {\large \frac{n·(n-1)}{2·i^2}}\).

由于\(f_0=0\),因此可以从 \(0\) 递推到 \(f_{count}\)。

时间复杂度:\(O(nlogp)\).

代码

#include <bits/stdc++.h>
#define endl '\n'
#define LL long long
using namespace std;

const int mod = 998244353;

int qmi(int m, int k, int p)
{
    int res = 1;
    while(k) {
        if(k & 1) res = (LL)res * m % p;
        m = (LL)m * m % p;
        k >>= 1;
    }
    return res;
}

void solve()
{
    int n;
    cin >> n;

    int cnt[2] = { 0 };
    vector<int> a(n + 1);
    for(int i = 1; i <= n; ++ i) {
        cin >> a[i];
        ++ cnt[a[i]];
    }

    int __count = 0;
    for(int i = 1; i <= cnt[0]; ++ i) {
        __count += a[i] == 1;
    }

    vector<int> f(__count + 1);
    for(int i = 1; i <= __count; ++ i) {
        f[i] = f[i - 1];
        f[i] += n * (n - 1LL) % mod * qmi(2LL * i * i % mod, mod - 2, mod) % mod;
        f[i] %= mod;
    }
    cout << f[__count] << endl;
}

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    int test;
    cin >> test;
    while(test--) solve();

    return 0;
}

标签:count,cnt,le,int,Codeforces,829,数组,Div
From: https://www.cnblogs.com/jakon/p/16821112.html

相关文章

  • Codeforces Round #830 (Div. 2)
    AB太简单了,不写解法了。CF1732CSheikh我们观察一下\(f(l,r)=\mathrm{sum}(l,r)-\mathrm{xor}(l,r)\)的性质。考虑假如一个数\(x\),对\(\mathrm{sum}\)的贡献为\(......
  • Codeforces Round #829 (Div. 2) E Wish I Knew How to Sort
    WishIKnewHowtoSort概率dp设计一个\(dp[i]\)表示还需要进行\(i\)次有效移动的概率何为有效移动?最后的数组是\(0\)在左边,\(1\)在右边因此只有把两个在错误......
  • Codeforces Round #829 (Div. 2) D Factorial Divisibility
    FactorialDivisibility模拟合....合成大西瓜?枚举每个阶乘因子,提取公因式之后有很多散着的\(1\),然后判断能不能合成当前倍数#include<iostream>#include<cstdio>#......
  • Codeforces Round #829 (Div. 1/Div. 2) 1753 A B C D 题解
    Div1A/2C.MakeNonzeroSum令最后每个\(a_i\)的系数为\(c_i\)(\(c_i=1/-1\)),发现只要满足\(c_1=1\)(下标从1开始),且c中没有两个-1相连,就一定能找出一种划分方式。那我......
  • Codeforces Round #830 C1. Sheikh(Easy version)
    题意给定一个长为\(n\)的非负整数序列\(\{a_n\}\),求\(l,r\)使\(f(l,r)=\text{sum}(l,r)-\text{xor}(l,r)\)最大,若答案不唯一,使\(r-l\)尽可能小,若仍不唯一,输出任意答案。......
  • Codeforces Round #747 (Div. 2) D Educational Codeforces Round 115 D
    D.TheNumberofImposters显然我们对于每一个关系就相当于连一个无向边我们显然对于每一个连通块来讲我们确定其中一个也就确定了这个连通块里的所有就相当于二分图......
  • Codeforces Round #829 (Div. 2)
    咕咕咕。C2.MakeNonzeroSum(hardversion)易得有奇数个非零值时无解。现在考虑将相邻的两个非零值配对,只要每一个非零值对都搞成和为零,总的和就为零。由于非零值只......
  • Educational Codeforces Round 137 (Rated for Div. 2) A-F
    比赛链接A题解知识点:数学。\(4\)位密码,由两个不同的数码组成,一共有\(C_4^2\)种方案。从\(10-n\)个数字选两个,有\(C_{10-n}^2\)种方案。结果为\(3(10-n)(9-n)\)......
  • Codeforces Round #829 (Div. 2) D. Factorial Divisibility(数学)
    题目链接题目大意:\(~~\)给定n个正整数和一个数k,问这n个数的阶乘之和能不能被k的阶乘整除既:(a\(_{1}\)!+a\(_{2}\)!+a\(_{3}\)!+....+a\(_{n}\)!)\(~\)%\(~\)k!\(~\)==......
  • Codeforces 1682 D Circular Spanning Tree
    题意1-n排列,构成一个圆;1-n每个点有个值0或者1,0代表点的度为偶数,1代表点的度为计数;询问能否构成一棵树,树的连边在圆内不会相交,在圆边上可以相交,可以则输出方案。提示1.......