最近做題小結

LteShuai發表於2024-10-23

https://www.luogu.com.cn/problem/AT_abc373_e

這道題是個二分 然後標答是兩個二分 我用的樹組+二分
需要對代數式進行拆分才能得到
我一開始看錯題目了 看成大於等於他的票的人不多於M就行
然後就很簡單 我覺得可以改編下這個題

很明顯 最終前m個人一定當選

那麼對於每一個人 我們就是儘量求他能不能利用最後的票讓自己當選
求這個票的最小值

那我們先進行排序 從小到大排好

對於已經排前M的人來說 我們把他給抹掉 然後讓m+1的人變成m位
此時我們對他進行二分判斷最小 因為雖然我已經排前m了 但是
票數多太多的情況下 還是會被反超

對於這個抹掉可以寫一個change函式 然後 後面再加上去就行

難就難在這個樹狀樹組的寫法上

現在分情況討論 如果我已經前m位了 現在我刪掉自己
二分了一個 ans可以進前m位的第2假設m為5 此時 假設多的票數總共是sum
sum-ans要讓3 4 5 不可以反超 則有後面的總和加上sum-ans小於等於3*(ans+ai)這樣就可以做到了

說白了就是後面的所有票數要小於人數*(ai+ans+1)

不能等於

這種求和用樹組是log操作 明顯可以做 對於查詢位置 可以
內建lowerbound upperbound進行查詢

為了查多少名不是透過low upp 因為他們返回的是數值
所以必須開再一開一個樹組進行訪問

struct Tree{
	int tr[range];
    void modify(int x,int d)
	{
		int dex=lower_bound(num+1,num+1+cnt,x)-num;
		//位置 xx
		for(int i=dex;i<=cnt;i+=i&-i)
		{
			tr[i]+=d;
		}
//		for(int i=dex;i<=cnt;i+=i&-i)
//		{
//			cout<<tr[i]<<" "<<i<<" "<<x<<" "<<dex<<endl;
//		}
	}
     int  query(int x)
	{
		int res=0;
		int dex=upper_bound(num+1,num+1+cnt,x)-num-1;
//		cout<<dex;
//		for(int i=dex;i>=0;i-=i&-i)
		for(int i=dex;i;i-=i&-i)
		{
		res+=tr[i];
		}	
//		cout<<"res:"<<res<<endl;
		return res;
	}	
}t1,t2;

挺不容易的

考慮建樹 只需要 列舉前m位


	k=k-sum;
	sort(num+1,num+1+cnt);
	cnt=unique(num+1,num+1+cnt)-num-1;
	sort(a+1,a+1+n,cmp);
//離散 
	for(int i=1;i<=m;i++)
	{
		t1.modify(a[i].x,a[i].x);
		t2.modify(a[i].x,1);
	}

後面刪除:

if(i<=m)
		{
	    t1.modify(a[i].x,-a[i].x);
        t2.modify(a[i].x,-1);
		t1.modify(a[m+1].x,a[m+1].x);
		t2.modify(a[m+1].x,1);	
		}		

這題就這樣了 難!

相關文章