题目大意
介于来看题解的小伙伴一半都是来看题目翻译的,我们在这里先把题目大致意思说明一下。(其实是我想看没看懂别的博客的翻译)
首先告诉你一个长度为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");
}
}