*点击

[Usaco2003 Open]Lost Cows

题目

Description

N (2 <= N <= 8,000) cows have unique brands in the range 1..N. In a spectacular display of poor judgment, they visited the neighborhood 'watering hole' and drank a few too many beers before dinner. When it was time to line up for their evening meal, they did not line up in the required ascending numerical order of their brands.

Regrettably, FJ does not have a way to sort them. Furthermore, he's not very good at observing problems. Instead of writing down each cow's brand, he determined a rather silly statistic: For each cow in line, he knows the number of cows that precede that cow in line that do, in fact, have smaller brands than that cow.

Given this data, tell FJ the exact ordering of the cows.

Input

* Line 1: A single integer, N

* Lines 2..N: These N-1 lines describe the number of cows that precede a given cow in line and have brands smaller than that cow. Of course, no cows precede the first cow in line, so she is not listed. Line 2 of the input describes the number of preceding cows whose brands are smaller than the cow in slot #2; line 3 describes the number of preceding cows whose brands are smaller than the cow in slot #3; and so on.

Output

* Lines 1..N: Each of the N lines of output tells the brand of a cow in line. Line #1 of the output tells the brand of the first cow in line; line 2 tells the brand of the second cow; and so on.

Sample Input

5
1
2
1
0

Sample Output

2
4
5
3
1


题目翻译

N(2 <= N <= 8,000)头母牛在1..N范围内拥有独特的品牌。为了显示出糟糕的判断力,他们参观了附近的“水坑”,并在晚餐前喝了太多啤酒。当需要排队享用晚餐时,他们并没有按照品牌要求的升序排列。

遗憾的是,FJ无法对它们进行排序。此外,他不太擅长观察问题。他没有写下每个奶牛的品牌,而是确定了一个相当愚蠢的统计数据:对于每个奶牛,他都知道在该奶牛之前的奶牛数量实际上比该奶牛的品牌小。

根据这些数据,告诉FJ奶牛的确切顺序。


思路:

分析样例可看出,第一头牛前面是没有牛的,所以样例输入就从第二头牛开始;

这样就不好确定的第一头的高度,所以可以从后往前推,先确定最后一头牛的高度;

那么我们来逆序分析题目样例:

输入

5

1 2 1 0

输出

2 4 5 3 1

可以定义一个f[i], f[i]=1 表示这个高度还没有确定,f[i]=0 表示这个高度已被一头牛占用;

然后可以把f[i]数组一开始都为1;

最后一头牛前面比他矮的牛是0个,那么最后一头牛的高度肯定是1,f[1]=0;

倒数第二头牛前面比他矮的牛是1个,那么它的高度不能是1,因为前面有一个比他矮的牛,所以它的高度不能是2,所以它的高度只能是3;

这样我们会发现一头牛的高度就是 f[i]中从下标1-n数第a[i]+1个1的位置;

比如最后一头牛a[i]=0, 就是从f 数组中从1-n数第1个1的位置,也就是1,然后f[1]=0;

倒数第二头牛a[i]=1,就是从f 数组中从1-n数第2个1的位置,也就是3,  然后f[3]=0;

这样,我们就可以确定每一头牛的高度了,那么怎么找f 数组时更快呢,自然想到的是树状数组;

我们知道树状数组可以很快地统计前缀和;

那么如果f 数组 1-x的前缀和中sum[x]==a[i]+1说明x则是第a[i]+1个1的位置,也说明这头牛的高度就是x

所以只需要枚举查找一遍就好了,枚举查找可以用二分,二分查找多么好

 

代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline ll read()
{
    ll a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
ll n,m,a[100010],sum[100010],ans[100010];
inline ll lowbit(ll x)
{
    return x&(-x);
}
inline void work(ll x,ll y)//work 就是实现当一个sum的值改变后,整个sum前缀的变化 
{
    while(x<=n)
    {
        sum[x]+=y;
        x+=lowbit(x);
    }
}
inline ll find(ll x)
{
    ll ans=0;
    while(x)
    {
        ans+=sum[x];
        x-=lowbit(x);
    }
    return ans;
}//别告诉我上面树状数组基本函数你不会 
inline ll findout(ll x)//二分(不要告诉我你不会二分) 
{
    ll l=1,r=n;
    while(l<r)
    {
        ll mid=(l+r)>>1;
        if(find(mid)<x)
            l=mid+1;
        else
            r=mid;
    }
    return l;
}
int main()//具体最好看思路 
{
    n=read();
    for(ll i=2;i<=n;i++)
        a[i]=read();
    for(ll i=1;i<=n;i++)
        work(i,1);//相当sum[i],一开始为1,然后统计前缀 
    for(ll i=n;i>=1;i--)
    {
        ll x=findout(a[i]+1);//二分查找一个与a[i]+1相等的前缀值 
        work(x,-1);//标记这个高度使用过了 
        ans[i]=x;
    }
    for(ll i=1;i<=n;i++)
        printf("%lld\n",ans[i]);
}

 

 估计是全网最详细的题解了

posted @ 2020-06-13 21:39  木偶人-怪咖  阅读(246)  评论(0编辑  收藏  举报
*访客位置3D地图 *目录