题意:
就是给你一个都是0和1的数组,然后每次随机选择两个不同的位置i<j。如果va[i]<va[j],那么交换这两个位置的值,然后问你期望操作操作多少次,可以使得这个数组变成单调不下降数组。
思考:
- 又是那种经常考的思维+期望题,肯定不能直接枚举先处理那些0或者1,去硬做。如果期望dp呢?这又没有递推性质,也不是推的。那么应该就是一个思维套在了上面。
- 那么既然都是01序列,看看一共有多少1,比如有x个1,那么就看看右边x位中有多少不是1,那么这些位置就是需要换的。比如t位需要换的,那么剩下的t位1肯定也是在左边。每次选择当还需要修改t对的时候,选择一对10的概率就是t*(t-1)/C(n,2)。但是顺序怎么办呢?先处理哪个再处理哪个?这样肯定就复杂了。那么就转化为,还剩下i对要换的时候,换成功一对的期望次数 ,E(x) = 1/p(x)。那么E(总) = E(x)的累加。
- 对于期望题,肯定最简单的去处理求概率期望啥的,那种复杂方法肯定是行不通的,最多可以处理数据比较小的数据,可以手玩一下。大部分情况下只要感觉有点复杂,那么就要转化,转化成比较简单的方式。
- 其实本题的思维方式,就是问你随机出n个数的期望次数,也是分步之后累加起来。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 998244353,inf = 1e18;
const int N = 2e5+10,M = 2010;
int T,n,m,k;
int va[N];
int ksm(int a,int b)
{
int sum = 1;
while(b)
{
if(b&1) sum = sum*a%mod;
a = a*a%mod;
b >>= 1;
}
return sum;
}
signed main()
{
IOS;
cin>>T;
while(T--)
{
cin>>n;
int mid = 0;
for(int i=1;i<=n;i++) cin>>va[i],mid += (va[i]==1);
int sum = 0,ans = 0;
for(int i=n-mid+1;i<=n;i++) sum += (va[i]==0);
for(int i=sum;i>=1;i--)
ans = (ans+n*(n-1)/2%mod*ksm(i*i%mod,mod-2)%mod)%mod;
ans = (ans%mod+mod)%mod;
cout<<ans<<"\n";
}
return 0;
}
总结:
多多思考。