Why Did the Cow Cross the Road I II III 三连击

Description

第一题

在这里插入图片描述

第二题

在这里插入图片描述

第三题

在这里插入图片描述

题解

T1

你会发现,我们可以先固定一个序列a,然后把另外一个序列b按照a的顺序标一下号。
然后题意就变成了求b的逆序对数。
而首尾交换其实就是这样:
假设当前交换的数为 i i i,那么逆序对数 a n s = a n s + ( i − 1 ) − ( n − i ) ans=ans+(i-1)-(n-i) ans=ans+(i1)(ni)
也就是加上小于i的数的个数,减去大于i的数的个数。

那么两个序列都做一遍就好了。

T2

先列一个 O ( n 3 ) O(n^3) O(n3)的方程。

由于我们的限制是小于4的。
那么意味着我们只有9种转移的状态。
然后我们再随便用一下树状数组维护一下即可。

T3

这题可谓是最难且最为麻烦的一道了吧。(相对的,其实还是很基础)

其实我们发现,我们只要满足三个条件就对答案有贡献:
a [ i ] > a [ j ] a[i]>a[j] a[i]>a[j]
b [ i ] < b [ j ] b[i]<b[j] b[i]<b[j]
a b s ( i − j ) < = K abs(i-j)<=K abs(ij)<=K
裸的三维偏序。

然后我™考试的时候以为数组越界没切。
好菜啊~

标程

T1
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const int maxn=100010;

int n,m,a[maxn],b[maxn],d[maxn],e[maxn],jlb[maxn];
long long c[maxn*10];

int lowbit(int x)
{
	return x&(-x);
}

void modify(int i,long long k)
{
	while (i<=n)
	{
		c[i]=(c[i]+k);
		i+=lowbit(i);
	}
}

long long getans(int i)
{
	long long gg=0;
	int kk=0;
	while (i>0)
	{
		gg=(gg+c[i]);
		kk=lowbit(i);
		i-=kk;
	}
	return gg;
}

int main()
{
	freopen("mincross.in","r",stdin);
	freopen("mincross.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		e[a[i]]=i;
	}
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&b[i]);
		jlb[i]=b[i];
		d[b[i]]=i;
	}
	for (int i=1;i<=n;i++)
	{
		b[d[a[i]]]=n-i+1;
		modify(i,1);
	}
	long long ans=0;
	long long op=n; 
	long long answer=op*op;
	for (int i=1;i<=n;i++)
	{
		ans+=n-i+1-getans(b[i]);
		modify(b[i],-1);
	} 
	answer=min(answer,ans);
	for (int i=n;i>1;i--)
	{
		ans+=(n-b[i])-(b[i]-1);
		answer=min(answer,ans);
	}
	
	
	for (int i=1;i<=n;i++)
	{
		a[e[jlb[i]]]=n-i+1;
		modify(i,1);
	}
	ans=0;
	for (int i=1;i<=n;i++)
	{
		ans+=n-i+1-getans(a[i]);
		modify(a[i],-1);
	} 
	answer=min(answer,ans);
	for (int i=n;i>1;i--)
	{
		ans+=(n-a[i])-(a[i]-1);
		answer=min(answer,ans);
	}
	printf("%lld\n",answer);
}
T2
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const int maxn=100010;

int n,m,a[maxn],b[maxn],id[maxn],ans[maxn],jlb[maxn];
long long c[maxn*10];

void qsort(int l,int r)
{
	int i=l;int j=r;
	int m=b[(i+j)/2];
	while (i<=j)
	{
		while (b[i]<m) i++;
		while (b[j]>m) j--;
		if (i<=j)
		{
			swap(id[i],id[j]);
			swap(b[i],b[j]);
			i++;j--;
		}
	}
	if (l<j) qsort(l,j);
	if (r>i) qsort(i,r); 
}

int lowbit(int x)
{
	return x&(-x);
}

void modify(int i,long long k)
{
	while (i<=n)
	{
		if (c[i]>=k) return;
		c[i]=(k);
		i+=lowbit(i);
	}
}

long long getans(int i)
{
	long long gg=0;
	int kk=0;
	while (i>0)
	{
		gg=max(gg,c[i]);
		kk=lowbit(i);
		i-=kk;
	}
	return gg;
}

int main()
{
	freopen("nocross.in","r",stdin);
	freopen("nocross.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&b[i]);
		id[b[i]]=i;
	}
	for (int i=1;i<=n;i++)
	{
		int st=max(1,a[i]-4);
		int en=min(n,a[i]+4);
		for (int j=st;j<=en;j++)
		{
			ans[j]=getans(id[j]-1);
		}
		for (int j=st;j<=en;j++)
		{
			modify(id[j],ans[j]+1);
		}
	}
	printf("%d\n",getans(n));
}
T3
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const int maxn=200010;

int n,m,a[maxn],b[maxn],id[maxn],x[maxn],y[maxn],p[3][maxn],q[3][maxn],jl[100][3][maxn];
long long c[maxn*10],ans;

void qsort(int l,int r)
{
	int i=l;int j=r;
	int m=x[(i+j)/2];
	while (i<=j)
	{
		while (x[i]<m) i++;
		while (x[j]>m) j--;
		if (i<=j)
		{
			swap(x[i],x[j]);
//			swap(id[i],id[j]);
			i++;j--;
		}
	}
	if (l<j) qsort(l,j);
	if (r>i) qsort(i,r); 
}

int lowbit(int x)
{
	return x&(-x);
}

void modify(int i,long long k)
{
	while (i<=n)
	{
		c[i]=(c[i]+k);
		i+=lowbit(i);
	}
}

long long getans(int i)
{
	long long gg=0;
	int kk=0;
	while (i>0)
	{
		gg=(gg+c[i]);
		kk=lowbit(i);
		i-=kk;
	}
	return gg;
}


void solve(int dep,int ki,int l,int r)
{
	if (l==r)
	{
		p[ki][0]=1;
		p[ki][1]=id[l];
	}
	else
	{
		int mid=(l+r)/2;
		solve(dep+1,1,l,mid);
		for (int i=0;i<=p[1][0];i++) jl[dep][1][i+l]=p[1][i];
		solve(dep+1,2,mid+1,r);
		
		for (int i=0;i<=p[2][0];i++) q[2][i]=p[2][i];
		for (int i=0;i<=jl[dep][1][l];i++) q[1][i]=jl[dep][1][i+l];
		int xx=1;int yy=1;
		p[ki][0]=0;
		while (yy<=q[2][0])
		{
			while (y[q[2][yy]]<y[q[1][xx]] && xx<=q[1][0])
			{
				modify(q[1][xx],1); 
				p[ki][0]++;p[ki][p[ki][0]]=q[1][xx];
				xx++;
			}
			p[ki][0]++;p[ki][p[ki][0]]=q[2][yy];
			ans+=getans(q[2][yy]-m-1);
			ans+=xx-1-getans(min(n,q[2][yy]+m));
			yy++;
		}
		for (int i=1;i<=xx-1;i++)
		{
			modify(q[1][i],-1);
		}
		while (xx<=q[1][0])
		{
			p[ki][0]++;p[ki][p[ki][0]]=q[1][xx];
			xx++;
		}
	}
}

int main()
{
	freopen("friendcross.in","r",stdin);
	freopen("friendcross.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		x[a[i]]=i;
		id[i]=a[i];
	} 
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&b[i]);
		y[b[i]]=i;
	}
	qsort(1,n);
	solve(1,1,1,n);
	printf("%lld\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值