• 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;
    }
    
  • 相关阅读:
    Android SDK 在线更新镜像服务器
    Android Studio (Gradle)编译错误
    java ZIP压缩文件
    java文件操作(输出目录、查看磁盘符)
    JXL读取写入excel表格数据
    Linux命令zip和unzip
    Linux查看系统基本信息
    Ubuntu C++环境支持
    Linux开机执行bash脚本
    ubuntu中磁盘挂载与卸载
  • 原文地址:https://www.cnblogs.com/lokiii/p/11040732.html
Copyright © 2020-2023  润新知