POJ 2182 Lost Cows【題解報告|貪心|樹狀數組|二分】

題目鏈接

題目大意

每個奶牛都有一個編號,1- N 從第二個牛開始給出前面比她編號小的牛的個數,問你求牛的編號序列

思路分析

從後往前看,最後一頭牛可以確定它的號碼,因爲知道了前面有k頭比它小的,k+1即爲它號碼。記a[i]爲第i頭牛在它前面有多少頭牛號碼比它小的(即輸入值),那麼如何計算第k-1頭牛的編號?

我們從1到N進行遍歷,記錄a[k1]a[k-1]個沒有訪問過的編號(沒有訪問過即沒有被他之後的牛a[k]a[k]所使用的編號),那麼第a[k]a[k]個編號即該牛的編號,整個過程如下所示


#define inf 0x3f3f3f3f
#define ll long long
#define vec vector<int>
#define P pair<int,int>
#define MAX 8005

int N, vis[MAX], r[MAX], a[MAX];

int main() {
	while (scanf("%d", &N) != EOF) {
		a[0] = 0;
		for (int i = 1; i < N; i++)scanf("%d", &a[i]);
		memset(vis, 0, sizeof(vis));
		memset(r, 0, sizeof(r));

		for (int i = N - 1; i >= 0; i--) {
			int cnt = 0;
			for (int j = 1; j <= N; j++) {
				if (!vis[j]) {
					if (cnt == a[i]) {
						r[i] = j; vis[j] = 1;
						break;
					}
					cnt++;
				}
			}
		}

		for (int i = 0; i < N; i++)
			cout << r[i] << endl;
	}
}

當然這樣做的複雜度顯然是N2N^2的,這道題勉強可過,但是數據一多就涼了,因此我們可以進行進一步的優化,我們可以用樹狀數組表示每個編號前面有多少個沒被佔用,然後用二分找到答案。

#define lobit(x) x&-x
int c[8001],n,a[8001],ans[8001];
void add(int x,int num)
{
    while(x<=n)
    {
        c[x]+=num;
        x+=lobit(x);
    }
}
int ask(int x)
{
    int sum=0;
    while(x)
    {
        sum+=c[x];
        x-=lobit(x);
    }
    return sum;
}
int low(int x)//二分答案
{
    int l=1,r=n;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(ask(mid)+x<=mid) r=mid-1;
        else l=mid+1;
    }
    return l;
}
int main()
{
    scanf("%d",&n);
    a[1]=0;
    for(int i=2;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=n;i>=1;i--)
    {
        int w=low(a[i]+1);//找到位置
        ans[i]=w;//記錄答案
        add(w,1);//佔用該位置
    }
    for(int i=1;i<=n;i++)
      printf("%d\n",ans[i]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章