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);
}
這題就這樣了 難!