poj 2182

来源:互联网 发布:人工智能有哪些领域 编辑:程序博客网 时间:2024/05/21 08:38

     题目意思很忽悠人,其实和poj 2828一模一样。就是对于一个序列,其数值为前面比它小的数值个数,最后输出在此下标下每个值所对应的真是排名(很拗口,最好看看poj 2828,意思是一样的)

     这道题的解法很简单。对于给定序列从前往后扫描,对于每个数值a[i],每次顺序地把a[i]+1个元素删去(用个数组vis记录情况),则其实际排名则是最后循环j所停留的位置。

     可能说得很笼统,就先看一下这个O(n*n)的代码吧,看了就明白了:

 

  1. #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int M=8005;
    int a[M],c[M];
    int p[M];
    bool vis[M];
    int n;
  2. int main()
    {
     scanf("%d",&n);
     int i,j;
     for(i=2;i<=n;i++)
      scanf("%d",&a[i]);
     a[1]=0;
     
  3. for(i=n;i>0;i--)
     {
      int cnt=0;
      for(j=1;j<=n;j++)
       if(!vis[j])
       {
        cnt++;
        if(cnt==a[i]+1)
         break;
       }
      p[i]=j;
      vis[j]=1;
     }
     
  4. for(i=1;i<=n;i++)
      printf("%d/n",p[i]);
     return 0;
    }

     对于静态的数据统计问题,树状数组是个很不错的工具,这里树状数组的下标才是真正的排名,原理就是O(n*n)那个算法的思想,只是查询效率大大提高。

     以下是代码:

 

  1. #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int M=9000;
    int c[M];
    int a[M],p[M];
    int n;
  2. int lowbit(int n)
    {
     return n&(-n);
    }
  3. int getsum(int n)
    {
     int ans=0;
     while(n>0)
     {
      ans+=c[n];
      n-=lowbit(n);
     }
     return ans;
    }
  4. void update(int n,int num)
    {
     while(n<M)
     {
      c[n]+=num;
      n+=lowbit(n);
     }
    }
  5. int binsearch(int x)
    {
     int low=1,high=n;
     while(low<=high)
     {
      int mid=(low+high)>>1;
      int temp=getsum(mid);
      if(temp==x)
       return mid;
      else
      {
       if(x<temp)
        high=mid-1;
       else
        low=mid+1;
      }
     }
     return 0;
    }
  6. int main()
    {
     int i;
     memset(c,0,sizeof(c));
     scanf("%d",&n);
     a[1]=0;
     update(1,1);
     for(i=2;i<=n;i++)
     {
      scanf("%d",&a[i]);
      update(i,1);
     }
     for(i=n;i>0;i--)
     {
      int s=binsearch(a[i]);
      s++;
      while(getsum(s)!=a[i]+1)
       s++;
      a[i]=s;
      update(s,-1);
     }
     for(i=1;i<=n;i++)
      printf("%d/n",a[i]);
     return 0;
    }

     线段树同样也可以做出来,思想还是不变,这也许是算法美丽的地方吧,它的外在表现可以千变万化而思想实质则是永恒:

 

  1. #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int M=8010;
    struct Tree
    {
     int l,r;
     int cnt;
    }T[3*M];
    int a[M],ans[M];
    int n,N;
  2. void build(int l,int r,int p)
    {
     T[p].l=l;
     T[p].r=r;
     T[p].cnt=r+1-l;
     if(l==r) return ;
     int mid=(l+r)>>1;
     build(l,mid,p<<1);
     build(mid+1,r,p<<1|1);
    }
  3. void del(int x,int p)
    {
     if(T[p].l==T[p].r)
     {
      ans[n]=T[p].l;
      T[p].cnt=0;
      return ;
     }
     if(x<=T[p<<1].cnt)
      del(x,p<<1);
     else
      del(x-T[p<<1].cnt,p<<1|1);
     T[p].cnt--;
    }
  4. int main()
    {
     scanf("%d",&N);
     int i;
     a[1]=0;
     for(i=2;i<=N;i++)
      scanf("%d",&a[i]);
     build(1,N,1);
     for(n=N;n>0;n--)
     {
      del(a[n]+1,1);
     }
     for(i=1;i<=N;i++)
      printf("%d/n",ans[i]);
     return 0;
    }
原创粉丝点击