题意
输入一个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都检测一下以上两种情况是否发生,如果从头到尾都不会发生的话,就可以组成一个合法的序列,但是如果到了某一步发现必定会出现二者中的其中一个的话,那么就组成不了一个合法的序列。
我们分别解释一下。
第一种:
很好理解,直接出个样例解释。
检测样例:
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; }