UPC-5618 K-th K(构造)

题目描述
You are given an integer sequence x of length N. Determine if there exists an integer sequence a that satisfies all of the following conditions, and if it exists, construct an instance of a.

a is N2 in length, containing N copies of each of the integers 1, 2, …, N.
For each 1≤i≤N, the i-th occurrence of the integer i from the left in a is the xi-th element of a from the left.
Constraints
1≤N≤500
1≤xi≤N2
All xi are distinct.
输入
The input is given from Standard Input in the following format:

N
x1 x2 … xN
输出
If there does not exist an integer sequence a that satisfies all the conditions, print ‘No’. If there does exist such an sequence a, print ‘Yes’.
样例输入
3
1 5 9
样例输出
Yes

题意:原题位于AtCoder,给出一个长度为n的序列a,要我们构造长度为n^2的序列b,在这个构造序列中要求满足,对于序列a中的元素,我们将在序列b中的第a【i】个位置恰好第i次出现数字i,即,a【i】表示了下标i在a【i】的第i次出现位置,所有1~n个数字都必须出现n次。在满足了第a【i】位出现第i次后,后续数位上的出现不做要求。 若能构造出这样的序列b输出Yes,否则输出No.

根据题意模拟构造即可,首先根据每个下标I的第i次出现位置从小到大排序,我们将优先排列出现在较前位置的数字。使得位置靠前的数字能在前a【i】个位置中有足够的空间放置i-1个数量。

对于某一个数,当我们发现排列的指针在构造i-1个数量的i时,位置超过了a【i】,说明构造失败,直接输出No

在正向构造完之后,我们满足了每个数字应该在第a【i】位前放置i个i的条件,接下来就要满足整个序列中所有数的出现次数都是n的条件,接着刚才的指针向后填数,此时我们需要填的i的个数是n-pos个,此时注意,如果之前的val太大,那么序列的后半部分可能不够填n-pos个i,那么就要填在val之前,这样就会影响val的出现次数不是i,所以也是无解的情况,因此如果填数的指针小于val那么说明一定会影响到val的排位。

代码如下

#include<bits/stdc++.h>
using namespace std;
struct num
{
    int val,pos;
} a[508],b[508];
bool cmp(num a,num b)
{
    return a.val<b.val;
}
int ans[508*508];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        bool flag=true;
        memset(ans,0,sizeof(ans));
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i].val);
            b[i].val=a[i].val;
            b[i].pos=a[i].pos=i;
        }
        sort(b+1,b+n+1,cmp);
        int it=1;
        for(int i=1; i<=n; i++)
        {
            ans[a[b[i].pos].val]=b[i].pos;
            for(int j=1; j<b[i].pos; j++) ///在第val为之前要填充pos个pos
            {
                while(ans[it])it++;///只能在没有被填数的位置填
                ans[it]=b[i].pos;
            }
            if(it>a[b[i].pos].val)///若填充超量说明根本不够构造
            {
                printf("No\n");
                flag=false;
                break;
            }
        }
        if(!flag) continue;
        for(int i=1; i<=n; i++) ///对于所有数,先正向填充,保证在val前能填充够pos个
        {
            for(int j=1; j<=n-b[i].pos; j++) ///再继续填充,前pos个能保证的情况下,在剩余空位能填充够n个
            {
                while(ans[it])it++;
                if(it<a[b[i].pos].val)
                {
                    printf("No\n");
                    flag=false;
                    break;
                }
                ans[it]=b[i].pos;
            }
            if(!flag) break;
        }
        if(flag)printf("Yes\n");
//        for(int i=1; i<=n*n; i++)printf("%d ",ans[i]);
    }
}
posted @ 2018-04-30 10:35  KuroNekonano  阅读(113)  评论(0)    收藏  举报