POJ2182(Lost Cows)

最近在写遗传算法求TSP时看到了grefenstette编码,于是想起了这个题目,这题我原来是用线段树写的C语言提交的,用时157ms,刚用树状数组+二分写用C++提交只跑了47ms,感觉快了不少。

这题数学模型是:现有一个1到n的一个被打乱的排列,告诉你每个数的左边有多少个数比它小,显然第一个数左边没有比它小的数,求每个位置上的数。

grefenstette编码差不多,只是把左边改成了右边再加1,例如:8 6 7 5 3 4 1 2编码后是:8 6 6 5 3 3 1 1

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #define N 8010
 4 int a[N],c[N],f[N],n;
 5 void update(int k)
 6 {
 7   for(;k<=n;k+=(k&(-k))) f[k]++;
 8 }
 9 int getsum(int k)
10 {
11   int sum=0;
12   for(;k>0;k-=(k&(-k)))  sum+=f[k];
13   return sum;
14 }
15 int bs(int k)
16 {
17   int min=0,max=n,mid;
18   while(min+1!=max)
19   {
20     mid=(min+max)>>1;
21     if(mid-1-getsum(mid)<a[k])  min=mid;
22     else  max=mid;
23   }
24   return max;
25 }
26 int main()
27 {
28   while(~scanf("%d",&n))
29   {
30     a[1]=0;
31     for(int i=2;i<=n;i++) scanf("%d",&a[i]);
32     memset(f,0,sizeof(f));
33     for(int i=n;i>0;i--)
34     {
35       c[i]=bs(i);
36       update(c[i]);
37     }
38     for(int i=1;i<=n;i++) printf("%d\n",c[i]);
39   }
40   return 0;
41 }

这题太经典了,又用线段树(堆实现的)写了一遍,时间还是47ms。感觉这个思路更清晰,更巧妙。 

View Code
#include <stdio.h>
#define N 8002
int n,D;
int x[N],id[N];
int sum[4*N];
void init()
{
  int i;
  for(D=1;D<n+2;D<<=1);
  for(i=1;i<=n;i++) sum[i+D]=1;
  for(i=D-1;i;i--)  sum[i]=sum[i<<1]+sum[i<<1|1];
}
void update(int k)
{
  k+=D;
  sum[k]=0;
  for(;k^1;k>>=1) sum[k>>1]=sum[k]+sum[k^1];
}
int query(int k)
{
  int i;
  for(i=1;i<D;)
  {
    if(sum[i<<1]>=k)  i<<=1;
    else  k-=sum[i<<1],i=i<<1|1;
  }
  return i-D;
}
int main()
{
  int i;
  while(~scanf("%d",&n))
  {
    x[1]=0;
    for(i=2;i<=n;i++) scanf("%d",&x[i]);
    init();
    for(i=n;i;i--)
    {
      id[i]=query(x[i]+1);
      update(id[i]);
    }
    for(i=1;i<=n;i++) printf("%d\n",id[i]);
  }
  return 0;
}
原文地址:https://www.cnblogs.com/algorithms/p/2512002.html