0629-基础训练(二)

今天的测试,让我知道自己还有很多很多知识点的掌握不牢,发现自己代码能力很差,思维也不够好,蒟蒻感到深深地难过。但不管怎么样,一切杀不死我的,都会使我变得强大,我不会放弃挣扎的!我相信只要肯钻研,就无论如何也不会差到哪里去。

但求耕耘,不问收获

难过的难过了,该敲的代码还得敲,下面不多说,上题。

先从T2开始吧

2、排列(premu.cpp)

【题目描述】
对于一个 1 到 n 的排列,逆序数的定义为:排列中第i 位 ai 的逆序数就是 a1..ai-1 中比
ai 大的数的个数。另外用 pi 表示 a1,…,ai 的逆序数和(即 pi 为逆序数的前缀和)。若知道 n 和 pi,则就能求得原排列。
现在对于排列{ai},给出 n 和{pi},请你还原这个排列。

【输入格式】
第一行输入一个数正整数 n。
第二行输入n 个正整数,表示pi 。

【输出格式】
输出一行,共有 n 个数,表示排列 ai。

【样例输入】
3
0 1 2

【样例输出】3 1 2

【数据范围】
对于前 10%的数据:n≤10。对于前 30%的数据:n≤1,000。

对于 100%的数据:n≤100,000;pi≤100,000,000。

蒟蒻的心路历程:

拿到这道题后,发现暴力很容易,是的很容易超时。n^2的复杂度不是100000可以玩的,那怎么办呢,不管先写个暴力再说(大佬请无视此操作)大概可以骗50分左右。(暴力的代码就不放上来了,思路大致如下:首先根据它给的pi可以求出ai;其次从后往前扫,ai就代表该数是剩余序列(除去该数后面的序列)中的第几大数;然后再从n到1循环放数,然后就凉了,就TLE了)

那么现在来考虑是什么导致了n^2的复杂度,然后对其进行修改就是正解啦。

没错就是每次从n到1放数的时候炸掉了,那么就想个方便快捷的方法来找到第i大的值就ok啦

蒟蒻后来用的是树状数组(不会的同学,自己上网搜,蒟蒻本人口齿不清无法详细讲解),就AC啦,下面直接上代码

(树状数组每次跳跳跳很快的)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
inline int read(){
	char ch;
	int flag=1;
	while((ch=getchar())<'0'||ch>'9'){
		if(ch=='-') flag=-1;
	}
	int res=0;
	while(ch>='0'&&ch<='9') {
		res=res*10+ch-48;
		ch=getchar();
	}
	if(flag==-1) res=-res;
	return res;
}
int n,p[100009],a[100009],t[100009],ans[100009];
int Lowbit(int i)
{
	return i&(-i);
}
void add(int i,int c){
	while(i<=n){
		t[i]+=c;
		i=i+Lowbit(i);
	}
}
int query(int i){
	int res=0;
	while(i>0) {
		res+=t[i];
		i=i-Lowbit(i);
	}
	return res;
}
int main(){
	n=read();
	p[0]=0;
	int i,j;
	for(i=1;i<=n;++i)
	{
		p[i]=read();
		a[i]=p[i]-p[i-1];
	}
	for(i=1;i<=n;++i) add(i,1);
	for(i=n;i>=1;--i){
		int x=i-a[i],l=0,r=n;
		while(l<r-1){
			int mid=l+r>>1;
			if(query(mid)<x) l=mid;
			else r=mid;
		}
		ans[i]=r;
		add(r,-1);
	}
	for(i=1;i<=n;++i)
	{
		printf("%d ",ans[i]);
	}
	return 0;
}

下面总结一下二分答案的模板,因为真的很容易死循环!

注意注意二分的序列一定是有序的

如果是找单调递增序列中>=x的最小的那一个(最大值的前驱)

while(l<r){
    int mid=l+r>>1  //就是除以二  
    if(a(mid)<x) l=mid+1;
    else r=mid;
}
最终答案在l中

那么如果是单调递增序列中<=x的最大的那一个(最小值的后继)

while(l<r)
{
    int mid=l+r+1>>1;//不要问我为什么加1,反正不加会死 
    if(a[mid]<=x) l=mid; 
    else r=mid-1;
 }最终答案还是在l中

还有两道题,T1和T3 

等我下次更新~



猜你喜欢

转载自blog.csdn.net/weixin_42557561/article/details/80860662