AtCoder Grand Contest 008-D K-th K题解

题意

   输入一个N(1<=N<=500),再输入X1,X2,X3...Xi...XN,N个数(1≤xi≤N2),询问是否存在一个满足任意一个i(1<=i<=N)都满足从开头到Xi位置i恰好出现i次的序列。

思路

  首先,根据题目的意思,我们不难推导出,若Xi处恰好是第i个i,那么在Xi之前的所有位置里,最多且必须出现i-1次i

从本质上来说,如果不存在这样一个序列,只有两种情况。

第一种情况,一定有一个i,Xi之前放不下i-1个i。

第二种情况,一定有一个i,Xi之前的空位数大于所有当前能放的数字个数。

我们对每一个Xi都检测一下以上两种情况是否发生,如果从头到尾都不会发生的话,就可以组成一个合法的序列,但是如果到了某一步发现必定会出现二者中的其中一个的话,那么就组成不了一个合法的序列。

我们分别解释一下。

第一种:

很好理解,直接出个样例解释。

扫描二维码关注公众号,回复: 951929 查看本文章

检测样例:

3

1 2 3

首先对1进行检查,1前面共有0个空位,需要放下1-1=0个1,显然是可以个,所以1被放在了1位置。

然后对2进行检查,此时1已经被填在了1这个位置,2位置的前面依然是只有一个空位,但是在2位置的前面必须要把第一个2填上,才能在2位置填第二个2,产生了冲突,所以该样例是不能组成合法序列的。

第二种:

有点麻烦,在这里有必要解释一下什么是当前能放的数字。

题意中我们已经读出,在Xi前面的位子里最多填i-1个i。然而在Xi之后的位置中,对i的个数没有限制。所以这个当前能放的数字个数由两方面组成。

一方面是那些还没有放的数,如果第i个i的位置在当前考虑位置的后面,也就是说在当前位置之前,那么i最多可以填i-1个。

另一方面,那些在前面已经放过的数,因为他们已经没有了在后面必须放第多少个的限制条件,那么他们在当前位置之前最多可以放置N个。

这两方面加起来就是所有在当前位置之前能放的数字个数。显然,如果这个个数还要比前面的空位少,那么就不会把序列延续到Xi的位置,组不成一个到当前位置合法的序列,判断结束。

检测样例

3

5 6 7

首先对于1进行检验,在Xi之前有4个空位,然而能够填的数一共只有一个2和两个3,所以根本延续不到第5个空位,判断结束。

#include <iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
 
struct A{
  int pos,val;
}a[550];
 
bool cmp(A a,A b){
  return a.pos<b.pos;
}
int Left[250010];
 
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i].pos);
        a[i].val=i;
    }
    for(int i=1;i<=n*n;i++) Left[i]=i;
    for(int i=1;i<=n;i++){
     for(int j=a[i].pos;j<=n*n;j++) Left[j]--;
    }
    sort(a+1,a+1+n,cmp);
    int tot=n*(n-1)/2;
    int flag=0;
    for(int i=1;i<=n;i++){
        int pos=a[i].pos;
        int val=a[i].val;
        if(Left[pos]<val-1) {flag=1; break;}
        for(int j=pos;j<=n*n;j++) Left[j]-=(val-1);
        if(pos-1>tot) {flag=1; break;}
        tot=tot-(val-1)+n;
    }
    if(flag) printf("No\n");
    else printf("Yes\n");
    return 0;
}



猜你喜欢

转载自blog.csdn.net/qq_41652258/article/details/79993763