POJ 2182 Lost Cows(树状数组,暴力解法)
http://poj.org/problem?id=2182
题意:
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
Output
Sample Input
5 1 2 1 0
Sample Output
2 4 5 3 1
分析:
其实这道题目只要会手算用例就能暴力解决。
假设读入题目给的数组a[n],其中a[1]=0
这道题目只给出了在i之前且比位于第i个位置的值小的值有多少个,我们在纸上分析用例可知,最后一个数的值肯定是a[n]+1.
然后我们从后往前推,且初始化一个数组vis[n]为全1。vis[i]==1表示当前值为i的数还没出现。首先我们推出最后一个数的值为a[n]+1,所以我们标记vis[a[n]+1]=0,接着我们推n-1的值,假设a[n-1]=3,那么就是在n-1的数之前有3个还未出现的数比它小,那么我们从vis[1]开始扫描,找到第4个1的位置就是a[n-1]的值。然后把这第4个1的位置vis[x]标记0.接下去找n-2位置的值,以此类推即可。
AC代码:266ms
#include
#include
#include
using namespace std;
const int MAXN =10000;
int a[MAXN];//初始
int vis[MAXN];//标记1
int ans[MAXN];//最终计算的结果
int main()
{
int n;
while(scanf("%d",&n)==1&&n)
{
a[1]=0;
for(int i=2;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
vis[i]=1;
ans[n]=a[n]+1;
vis[ans[n]]=0;
for(int i=n-1;i>=1;i--)
{
int num = a[i];
int j;
for(j=1;i<=n;j++)
{
if(vis[j]==1)
{
num--;
if(num<0)
{
vis[j]=0;
break;
}
}
}
ans[i]=j;
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
}
return 0;
}
解法二:树状数组。初始时,树状数组为全0.sum(x)表示已经确定了值的且小于等于x的值的个数。
我们依然从后往前倒推,对于当前考虑的a[n],假设它的值为x,那么我们就执行add(x,1)。接下来我们要找到a[n-1]的值y,y肯定在[1,8000]范围内,所以可以用二分查找确定y的值。如果我们猜y=8的话,如果a[n-1]=4并且比8小的已经确定了的值即sum(7)=3,可以说明从1到7中:由有3个数的值已经确定了 并且 还有4个值没有确定且这些没确定值的比y小的数正好是4个,那么y肯定>=8。可以加大y的范围继续探测。如果sum(7)+4<7的话,8就比y本来的值要大了。
如果sum(7)+4>7的话,8就比y本来的值要小。
由此可得一般结论,我们猜测当前a[i]的值为y,如果
Sum(y-1)+a[i]==y-1 那么y为最小值
Sum(y-1)+a[i]
Sum(y-1)+a[i]>y-1 那么y+1为最小值
AC代码:0ms 注意if else语句的顺序,发生概率大的语句放前面。
#include
#include
#include
using namespace std;
const int MAXN =8008;
int a[MAXN];//初始
int ans[MAXN];//最终计算的结果
int c[MAXN];
int n;
int lowbit(int x)
{
return x&(-x);
}
int sum(int x)
{
int res=0;
while(x)
{
res +=c[x];
x-=lowbit(x);
}
return res;
}
void add(int x,int v)
{
while(x<=n)
{
c[x]+=v;
x+=lowbit(x);
}
}
int main()
{
while(scanf("%d",&n)==1&&n)
{
a[1]=0;
memset(c,0,sizeof(c));
for(int i=2;i<=n;i++)
scanf("%d",&a[i]);
ans[n]=a[n]+1;
add(a[n]+1,1);
for(int i=n-1;i>=1;i--)
{
int L=1,R=n;
while(R>L)
{
int mid = (R+L+1)/2;
if(sum(mid-1)+a[i] < mid-1)//这3个if else语句的顺序换一换 时间就可能是16ms 63ms 0ms等
R=mid-1;
else if(sum(mid-1)+a[i] == mid-1)
L=mid;
else
L=mid+1;
}
ans[i]=L;
add(ans[i],1);
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
}
return 0;
}