zoukankan      html  css  js  c++  java
  • codeforces1081G Mergesort Strikes Back【期望dp+脑洞】

    首先看这样做的特点,就是分到最后小块里的点合并上去的时候相对顺序不变,所以先加上块内逆序对的期望
    合并的时候一定是一边卡住一个大值,另一边跳指针,所以把一个值向右直到有大于它的值位置的一段区间看作一段
    当前合并两块合并到第i个和第j个,如果i和j都是块的开头就一定不会构成逆序对,因为双指针的时候会直接比较这两个点,其他情况有1/2的概率,所以成为一对逆序对的概率是( frac{i+j-2}{2(i+j)} )
    又因为最小快的长度最多两种,所以求前缀和然后枚举i直接求一排j的值即可

    #include<iostream>
    #include<cstdio>
    #include<map>
    using namespace std;
    const int N=100005;
    int n,k,mod,ans,inv[N],s[N];
    map<int,int>c;
    int ksm(int a,int b)
    {
    	int r=1;
    	while(b)
    	{
    		if(b&1)
    			r=1ll*r*a%mod;
    		a=1ll*a*a%mod;
    		b>>=1;
    	}
    	return r;
    }
    void pre(int l,int r,int k)
    {
    	if(k<=1||l==r)
    	{
    		c[r-l+1]++;
    		return;
    	}
    	int mid=(l+r)>>1;
    	pre(l,mid,k-1);
    	pre(mid+1,r,k-1);
    }
    int clc(int x,int y)
    {
    	int r=1ll*x*y%mod;
    	for(int i=1;i<=x;i++)
    		r=(r-2ll*(s[i+y]-s[i])%mod)%mod;
    	return r;
    }
    int main()
    {
    	scanf("%d%d%d",&n,&k,&mod);
    	for(int i=1;i<=1e5;i++)
    		inv[i]=ksm(i,mod-2),s[i]=(s[i-1]+inv[i])%mod;
    	pre(1,n,k);
    	for(map<int,int>::iterator i=c.begin();i!=c.end();i++)
    	{
    		ans=(ans+1ll*i->first*(i->first-1)%mod*inv[2]%mod*i->second%mod)%mod;
    		ans=(ans+1ll*i->second*(i->second-1)%mod*inv[2]%mod*clc(i->first,i->first)%mod)%mod;
    	}
    	for(map<int,int>::iterator i=c.begin();i!=c.end();i++)
    		for(map<int,int>::iterator j=c.begin();j!=c.end();j++)
    			if(i->first<j->first)
    				ans=(ans+1ll*clc(i->first,j->first)*i->second%mod*j->second%mod)%mod;
    	printf("%lld
    ",(1ll*ans*inv[2]%mod+mod)%mod);
    	return 0;
    }
    
  • 相关阅读:
    Linux基础命令-cp
    Linux基础命令-mkdir
    Linux基础命令-touch
    Linux基础命令-diff
    Linux基础命令-cut
    Linux基础命令-stat
    System.Web.HttpException: 请求在此上下文中不可用
    数据库日志删除、压缩操作
    如何收缩和删除SQL日志文件
    Excel 常用宏代码大全
  • 原文地址:https://www.cnblogs.com/lokiii/p/11040732.html
Copyright © 2011-2022 走看看