CF1945F Kirill and Mushrooms

兰亭一叙發表於2024-09-07

題意

營地裡的人一睡著,基里爾就偷偷溜出帳篷,去智者橡樹那裡採蘑菇。

眾所周知,橡樹下生長著 \(n\) 種蘑菇,每種蘑菇都有 \(v_i\) 的魔力。基里爾非常想用這些蘑菇製作一種魔力最大的靈藥。

靈藥的強度等於其中蘑菇的數量與這些蘑菇中最小魔力的乘積。為了配製靈藥,基里爾將依次採摘生長在橡樹下的蘑菇。基里爾可以按照任何順序採集蘑菇。

然而,事情並非如此簡單。智慧橡樹告訴基里爾從 \(1\)\(n\) 的數字 \(p\) 的排列組合。如果基里爾只採摘 \(k\) 蘑菇,那麼所有指數為 \(p_1, p_2, \dots, p_{k - 1}\) 的蘑菇的魔力就會變成 \(0\) 。基里爾不會使用魔力為零的蘑菇來配製靈藥。

你的任務是幫助基里爾採集蘑菇,使他能夠釀造出最大魔力的靈藥。不過,基里爾有點害怕在橡樹附近逗留太久,所以在所有適合採集蘑菇的選項中,他要求您找到蘑菇數量最少的那個。

長度為 \(n\) 的排列是由 \(n\) 個不同的整陣列成的陣列,這些整數的順序從 \(1\)\(n\) 。例如, \([2,3,1,5,4]\) 是一個排列,但 \([1,2,2]\) 不是排列( \(2\) 在陣列中出現兩次), \([1,3,4]\) 也不是排列( \(n=3\) ,但 \(4\) 在陣列中出現)。

思路

考慮列舉摘 \(k\) 個蘑菇,然後就可以獲得哪些蘑菇會歸 \(0\) , 則答案貪心的想即選前 \(k\) 個蘑菇
則最小值為當前序列第 \(k\)

支援修改且可以動態維護第 \(k\) 大的顯然是權值線段樹

程式碼

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
int a[N];
int b[N];
int v[N];
struct node
{
    int l,r;
    int sum;
}tr[N<<2];
void pushup(int id){tr[id].sum=tr[id<<1].sum+tr[id<<1|1].sum;}
void build(int id,int l,int r)
{
    tr[id]={l,r};
    if(l==r)
    {
        return;
    }
    int mid=(l+r)/2;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
}
void change(int id,int x,int v)
{
    if(tr[id].l==tr[id].r)
    {
        tr[id].sum+=v;
        return;
    }
    int mid=(tr[id].l+tr[id].r)/2;
    if(x<=mid) change(id<<1,x,v);
    else change(id<<1|1,x,v);
    pushup(id);
}
int find(int id,int k)
{
    if(tr[id].l==tr[id].r)
    {
        return tr[id].l;
    }
    if(k<=tr[id<<1|1].sum) return find(id<<1|1,k);
    else return find(id<<1,k-tr[id<<1|1].sum);
}
int main()
{
    int _;
    cin>>_;
    while(_--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+1+n);
        int m=unique(b+1,b+1+n)-b-1;
        build(1,1,m);
        for(int i=1;i<=n;i++)
        {
            a[i]=lower_bound(b+1,b+1+m,a[i])-b;
            change(1,a[i],1);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&v[i]);
        }
        long long ans=b[m];
        int id=1;
        for(int i=2;i<=n;i++)
        {
            if(n-i+1<i) break;
            change(1,a[v[i-1]],-1);
            long long cnt=1LL*b[find(1,i)]*i;
            if(cnt>ans)
            {
                ans=cnt;
                id=i;
            }
        }
        cout<<ans<<" "<<id<<"\n";
    }
}