1. 程式人生 > 其它 >10.13多校聯訓

10.13多校聯訓

題意略。

T1 AT2672 [AGC018C] Coins

Sol
考場上面想的是六遍貪心做法,可惜寫了300行使用替換功能的時候C++死了,心態爆炸就沒再寫。事後證明演算法是正確的,但是碼量上並不優秀。
這是我當時考試的解法:首先有個顯然的貪心:每個人儘可能去取他有的最多的幣種。但是會出現有的幣種大家都多,而有的又缺的情況,所以需要調配多人的幣種。接下來還可以證明的是對於三個幣種的調配,一定是無環的,即如果有人從金幣調到了銀幣,那就不會有銀幣調到金幣,因為這樣就不如他們都不調;三個的環同理。因此處於調配圖的頂端的幣種是不受其他幣種的影響的,直接貪心,然後順次貪心即可。但是無法確定順序,所以列舉所有的六種貪心順序取最值即可。由於碼量巨大,所以其實並不可取。
題解的優質解法是這樣的:假設每個人都取金幣,然後題目就變成了從\(n\)

個人中選\(Y\)個人取\(B_i-A_i\)個幣,選\(Z\)個人取\(C_i-A_i\)個幣,求最大值。把這\(n\)個人按照\(B_i-C_i\)從大到小排序,顯然有改選銀幣的人全部在改選銅幣的人之前,從前往後用優先佇列維護前\(i\)個裡面選\(Y\)個的最值,從後往前維護後\(i\)個裡面選\(Z\)個的最值,最後列舉分界點求和的最值即可。
Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
    return f?x:-x;
}
const int maxn=100010;
int n,R,Y,G,ans,mx=-1e18;
priority_queue<int,vector<int>,greater<int> >qu1,qu2;
int maxb[maxn],maxa[maxn];
struct node
{
    int a,b;
    bool operator<(const node &x)const
    {
        return a-b>x.a-x.b;
    }
};
node dl[maxn];
signed main()
{
//    freopen("collection.in","r",stdin);
//    freopen("collection.out","w",stdout);
    R=read();Y=read();G=read();
    n=R+Y+G;
    for(int i=1;i<=n;i++)
    {
        int x=read(),y=read(),z=read();
        ans+=x;
        y-=x;z-=x;
        dl[i]=(node){y,z};
    }
    sort(dl+1,dl+n+1);
    if(Y)
    {
        for(int i=1;i<=Y;i++)
        {
            qu1.push(dl[i].a);
            maxb[i]=maxb[i-1]+dl[i].a;
        }
        for(int i=Y+1;i<=n;i++)
        {
            if(qu1.top()<dl[i].a)
            {
                maxb[i]=maxb[i-1]-qu1.top()+dl[i].a;
                qu1.pop();qu1.push(dl[i].a);
            }else maxb[i]=maxb[i-1];
        }
    }
    if(G)
    {
        for(int i=1;i<=G;i++)
        {
            qu2.push(dl[n-i+1].b);
            maxa[n-i+1]=maxa[n-i+2]+dl[n-i+1].b;
        }
        for(int i=G+1;i<=n;i++)
        {
            if(qu2.top()<dl[n-i+1].b)
            {
                maxa[n-i+1]=maxa[n-i+2]-qu2.top()+dl[n-i+1].b;
                qu2.pop();qu2.push(dl[n-i+1].b);
            }else maxa[n-i+1]=maxa[n-i+2];
        }
    }
    for(int i=Y;i<=n-G;i++)mx=max(mx,maxb[i]+maxa[i+1]);
    printf("%lld\n",ans+mx);
    return 0;
}

T2 AGC記不得了

Sol
真的不會。考場上因為有70的部分分都是修改操作很少的,所以直接合並相同操作的區間然後暴力。正解是按照從低位到高位建一顆\(0,1,2trie\)樹,對於每次的0操作可以直接換子節點,1操作由於是從低到高修改,所以每次修改的複雜度不超過\(O(n)\)
Code
無。

T3 CF960H Santa's Gift

Sol
把柿子化一下就完了,樹剖線段樹維護修改即可(亂寫的)。
Code
更莫得。

T4 CF????

總之就3500的題,爬了。