题解:「GLR-R3」雨水

前言

先吐槽一下,这个英文是真的坑。

const int MAXN = 712; // Set a right value according to your solution.

为啥不能直接把数组下标设为最大值呢,还要挖个坑考考英文。

然后这个随机数据卡不掉 \(O(n^2)\) 做法啊,感觉大为震撼。

正文

更简化的题意

给定一个序列 \(A\),从中选取下标单调递增的一些数,相邻的两两交换,但仅局限于下标为奇数的和它右边的数这样交换,再放回原序列,使得新得到的序列字典序尽可能小。

解题

一道很不错的贪心,对于字典序最小,假设我们只能换一次,那肯定将整个序列里面最小的那个数换到最前面。推广到多次操作,再交换的数肯定只能从最小的那个数右边去找,否则不符合操作规则。

对于如果有多个最小的数,我们应该交换哪一个呢?因为字典序尽可能小,同样可以推出大的应该尽可能往后放,因此在寻找最小的数时,要找下标更大的。

由此我们可以倒序跑一遍记录下对于每一个数它的右侧的最小值,再正着跑一遍进行交换操作,这样的总时间复杂度就是 \(O(n)\)

答案自然溢出即可。

Code

#include<bits/stdc++.h>
#define ull unsigned long long
#define MAX 10000002
#define INF 999999999
using namespace std;

int n,a[MAX];

namespace Generator
{
	ull k1,k2;
	int thres;
	inline ull xorShift128Plus()
	{
		ull k3=k1,k4=k2;
		k1=k4,k3^=(k3<<23),k2=k3^k4^(k3>>17)^(k4>>26);
		return k2+k4;
	}
	inline void generate()
	{
		for(int i=1;i<=n;i++)
			a[i]=xorShift128Plus()%thres;
	}
}

unsigned int key[MAX],pos[MAX];
ull ans;
inline void work()
{
	key[n+1]=INF;
	for(int i=n;i>=2;i--)
	{
		key[i]=key[i+1],pos[i]=pos[i+1];
		if(a[i]<key[i]) key[i]=a[i],pos[i]=i;
	}
	int mink,minp;
	for(int i=1;i<n;i++)
	{
		mink=key[i+1],minp=pos[i+1];
		if(mink<a[i]) swap(a[i],a[minp]),i=minp;
	}
	return;
}

int main()
{
	scanf("%d",&n);
	scanf("%llu %llu %d",&Generator::k1,&Generator::k2,&Generator::thres);
	Generator::generate();
	work();
	for(int i=1;i<=n;i++)
		ans+=(unsigned long long)a[i]*i;
	cout<<ans;
	return (0-0);
}
posted @ 2022-08-24 17:58  LgxTpre  阅读(17)  评论(0编辑  收藏  举报