Luogu P11158 【MX-X6-T4】夢重力 题解

P11158 【MX-X6-T4】夢重力

分类讨论好题。

不难发现交换行等价于交换列,考虑转化贡献体,枚举长度为 n2 区间,统计这个区间被多少种交换方式包含。

考虑一个长度为 n2 区间满足要求的充要条件是存在一段空权值区间 [x,x+n2] 使得区间中所有 pi 不属于 [x,x+n2]。注意到如果存在满足要求的区间则其余每一行都必然有数,且上边界必然在 [n2+1,n],下边界必然在 [1,n2],所以我们维护 [1,n2] 中的最大值和 [n2+1,n] 中的最小值即可判定是否存在满足要求的区间。可以使用 set 维护。

如果这个区间本身就满足要求,那么在区间内部交换或区间外部交换没有影响,对答案贡献 n2×(n21)2×2=n2×(n21)。但是如果 [1,n2] 中有数,我们可以把 [1,n2] 中的最大值换成一个较小的上边界,同样满足条件。如果 [n2+1,n] 中有数同理。需要特判一下。

如果这个区间本身不满足要求,还是有可能通过交换得到满足要求的区间。不难发现此时一定是换掉 [1,n2] 中的最大值或 [n2+1,n] 中的最小值,于是我们分别计算一下换掉之后的区间大小即可。注意如果换掉之后空权值区间长度大于 n2,则有两种换法,如果空权值区间长度等于 n2,则只有一种换法。这个结论手玩一下不难发现。

然后就做完了,时间复杂度 O(nlogn)

#include <bits/stdc++.h>
using namespace std;
long long n,a[500000],cs=0,cb=0,ans=0;
set<long long>q;
int main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	q.insert(0),q.insert(n+1);
	for(int i=1;i<=n/2;i++)q.insert(a[i]);
	for(int i=1;i<=n/2+1;i++)
	    {
	    set<long long>::iterator mx=q.lower_bound(n/2+1),mi=q.upper_bound(n/2),tmp=mx;
	    mi--;
	    if((*mx)-(*mi)-1>=n/2)
	       {
		   ans+=(n/2)*(n/2-1);
		   if((*mx)!=n+1)ans++;
		   if((*mi)!=0)ans++;
	       }
	    else
		    {
		    mx++;
		    if((*mx)-(*mi)-1>n/2)ans+=2;
		    else if((*mx)-(*mi)-1==n/2)ans++;
		    mx=tmp,mi--;
		    if((*mx)-(*mi)-1>n/2)ans+=2;
		    else if((*mx)-(*mi)-1==n/2)ans++;
		    }
	    q.insert(a[i+n/2]),q.erase(a[i]);
		}
	printf("%lld\n",ans);
	return 0;
}
posted @   w9095  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示