D. Rating Compression

D. Rating Compression

题目链接

题目大意

介于来看题解的小伙伴一半都是来看题目翻译的,我们在这里先把题目大致意思说明一下。(其实是我想看没看懂别的博客的翻译)

首先告诉你一个长度为N的数组,接着利用K来压缩数组,所谓压缩,就是把数组第i个元素改变为区间【i,i+k】元素的最小值,问压缩后的数组能否满足

1.所有元素都不重复。
2.所有元素都在【1,N-K+1】范围之内。
在一行输出一个序列从1的压缩到N的压缩能否满足上述条件,能在该压缩成度K的位置输出1,否则输出0。

暴力尝试

没什么好说的,就是用双指针维护区间的最小值,连着扫描n次,毫无疑问T掉了,呜呜呜(

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
int s[300001];
char box[4000000];
int mloc(int l,int r){
	int minn=10100000,loc=-1;
	for(int i=l;i<=r;i++){
		if(minn>s[i]){
			loc=i;
			minn=s[i];
		}
	}
	return loc;
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		memset(s,0,sizeof s);
		for(int i=0;i<n;i++){
			scanf("%d",&s[i]);
		}
		for(int i=0;i<n;i++){
			int loc=-1,OK=1;
			memset(box,0,sizeof box);
			for(int j=0;j+i<n;j++){
				if(loc>=j){
					if(s[j+i]<=s[loc]){
						loc=j+i;
					}
				}else{
					loc=mloc(j,j+i);
				}
				if(box[s[loc]]==0&&s[loc]<=n-i){
					box[s[loc]]++;
				}else{
					OK=0;
					break;
				}
			}
			printf("%d",OK);
		}
		printf("\n");
	}
}
 

正解

通过简单的分析我们可以得到下面这样的性质

1.如果第K个压缩成立,且在第K个压缩产生N-K+1的序列中删除边缘的一个数字能改变这个序列的最小值为最小值+1(不太好理解,下面在解释一下 ),那么K-1个压缩一定成立。

举个例子,首先我们先以整个数列为一个序列
1 3 5 2 4
我们发现再边缘的位置(高亮部位,1,4)存在序列最小值1,于是我们删除1。
1 3 5 2 2
改变了序列的最小值1,并且次小值2存在,因此K=N-2+1的压缩满足要求。
而接着讨论这串数组
3 5 2 2
删掉任意边界值都不能改变最小值2
因此K=N-3+1时不满足。
这里我们可以开个桶,这样我们就很容易发现序列中是否有重复的数值。

2.如果第K个压缩不合法,那么第K-1个的压缩也不合法。

举个简单的例子,你肯定一下子就明白了
当K=3时
1 6 3 2 5 7 4
1 6 3 2 5 7 4
当K=2时:
1 6 3 2 5 7 4
1 6 3 2 5 7 4

3.如果K=1时,上面两条结论不成立。(看这里之前你肯定想到了)

这里就不在赘述了。

代码

最后放上代码,没有代码的题解等于_____(填空题,自己脑补)

//写的不好看,回来有空再改的漂亮些
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
int s[300001];
char box[4000000],an[300001];
int mloc(int l,int r){
	int minn=10100000,loc=-1;
	for(int i=l;i<=r;i++){
		if(minn>s[i]){
			loc=i;
			minn=s[i];
		}
	}
	return loc;
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		memset(an,1,sizeof an);
		memset(box,0,sizeof box);
		int n;
		scanf("%d",&n);
		memset(s,0,sizeof s);
		for(int i=0;i<n;i++){
			scanf("%d",&s[i]);
			box[s[i]]++;
		}
		//特判K=1 
		for(int i=1;i<=n;i++){
			if(box[i]==0){
				an[1]=0;
				break;
			}
		}
		int l=0,r=n-1,now=1;

		box[0]=1;
		while(l!=r){
			if(s[l]==now&&box[now-1]==1){
				now++;
				l++;
			}else if(s[r]==now&&box[now-1]==1){
				now++;
				r--;
			}else{
				if(box[now-1]==1&&box[now]!=0)now++;
				for(int i=n-now+1;i>1;i--){
					an[i]=0;
				}
				goto end;
			}
		} 
		end:
		for(int i=1;i<=n;i++){
			printf("%d",an[i]);
		}
		printf("\n");
	}
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值