地址:http://poj.org/problem?id=2182
题意:
N头奶牛排队,它们的身高为1~n,已知每头牛前面有多少头比自己矮,求每头牛的身高。
解析:
输入其实是从i=2开始的
暴力代码:跑了438M
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; const int maxn=8005; int vis[maxn]; int p[maxn]; int a[maxn]; int main() { int n; cin>>n; for(int i=2;i<=n;i++) cin>>p[i]; p[1]=0; int tot=1; for(int i=n;i>=1;i--) { int ans=0; int md=p[i]+1; for(int j=1;j<=n;j++) { if(!vis[j]) { ans++; if(ans==md) { a[tot++]=j; vis[j]=1; break; } } } } for(int i=n;i>=1;i--) { cout<<a[i]<<endl; } }
树状数组做法:
树状数组优化暴力代码的第二层for:剩余未被标记的数目
通过树状数组来维护一个0/1序列,c[i],表示小于等于 i 而且未被使用的数有几个。
add(1,1),add(2,1).....add(n,1)这样就维护了一个初始序列:
数: 1,2,3,4,5
它前面比它小的:1,2,3,4,5
从后往前看a[i],那么一个位置的数,就是未被使用的数中第a[i]+1大个
所以通过二分find(a[i]+1),找到一个数md,满足<=md且未被使用的数有a[i]+1个,输出它,
而且:update(md,-1),这个数被使用,那么后面自然都要-1
代码:47ms,比暴力快得不是一点~
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn=8e3+10; int c[maxn],a[maxn],b[maxn]; int n; int lowbit(int x) { return x&(-x); } void update(int id,int x) { for(int i=id;i<maxn;i+=lowbit(i)) c[i]+=x; } int getsum(int id) { int sum=0; for(int i=id;i>0;i-=lowbit(i)) sum+=c[i]; return sum; } int find(int x) { int l=1,r=n; int ok; while(l<r) { int md=(l+r)>>1; if(getsum(md)>=x) { r=md; } else l=md+1; } return r; } int main() { scanf("%d",&n); update(1,1); for(int i=2;i<=n;i++) { scanf("%d",&a[i]); update(i,1); } int tot = 1; for(int i=n;i>=1;i--) { int md=find(a[i]+1); b[i]=md; update(md,-1); } for(int i=1;i<=n;i++) cout<<b[i]<<endl; }