【AtCoder】ARC096(C - F)

據說日本題思惟都很棒,去漲漲智商qwqios

C - Half and Half

題解

枚舉買多少個AB披薩也行
可是關於買x個AB披薩最後的總花費是個單峯函數,能夠三分
這題有點像六省聯考2017D1T1送分題期末考試函數

代碼

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAXN 100005
#define PLI pair<long long,int>
#define fi first
#define se second
#define mp make_pair
//#define ivorysi
using namespace std;
typedef long long int64;
int64 A,B,C;
int X,Y;
int64 calc(int t) {
    return 2 * t * C + max(X - t,0) * A + max(Y - t,0) * B;
}
void Solve() {
    scanf("%lld%lld%lld%d%d",&A,&B,&C,&X,&Y);
    int L = 0,R = max(X,Y);
    while(1) {
        int k = (R - L) / 3;
        if(!k) break;
        if(calc(L + k) > calc(R - k)) L = L + k;
        else R = R - k;
    }
    int64 ans = X * A + Y * B;
    for(int i = L ; i <= R ; ++i) {
        ans = min(ans,calc(i));
    }
    printf("%lld\n",ans);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

D - Static Sushi

題解

分類瞎討論一下就好,順時針走,逆時針走,順時針走再去逆時針,逆時針走再去順時針spa

代碼

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAXN 100005
#define PLI pair<long long,int>
#define fi first
#define se second
#define mp make_pair
//#define ivorysi
using namespace std;
typedef long long int64;
int N;
int64 C,x[MAXN],v[MAXN],ans;
int64 pre[MAXN],suf[MAXN],premax[MAXN],sufmax[MAXN];
void Solve() {
    scanf("%d%lld",&N,&C);
    for(int i = 1 ; i <= N ; ++i) scanf("%lld%lld",&x[i],&v[i]);
    x[N + 1] = C;
    for(int i = 1 ; i <= N ; ++i) {
        pre[i] = pre[i - 1] + v[i] - (x[i] - x[i - 1]);
        premax[i] = max(pre[i],premax[i - 1]);
    }
    for(int i = N ; i >= 1 ; --i) {
        suf[i] = suf[i + 1] + v[i] - (x[i + 1] - x[i]);
        sufmax[i] = max(suf[i],sufmax[i + 1]);
    }
    ans = max(ans,max(sufmax[1],premax[N]));
    for(int i = 1 ; i <= N ; ++i) {
        ans = max(ans,pre[i] - x[i] + sufmax[i + 1]);
    }
    for(int i = N ; i >= 1 ; --i) {
        ans = max(ans,suf[i] - (C - x[i]) + premax[i - 1]);
    }
    printf("%lld\n",ans);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

E - Everything on It

題解

容斥,w(i)表示有i個配料出現小於2次
式子就是\(\sum_{i = 0}^{n}(-1)^{i}\binom{n}{i}w(i)\)
而後考慮求\(w(i)\)
再考慮一個\(w2(i,j)\)表示把i個數字分到j個碗裏,能夠有數字不分到碗裏,用相似第二類斯特林數的遞推方式能夠求出來
而後方案數就是\(w(i) = \sum_{j = 0}^{i} w2(i,j)2^{(N - i)j}2^{2^{N - i}}\)
而後就能\(O(n^2)\)出解了code

代碼

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAXN 100005
#define PLI pair<long long,int>
#define fi first
#define se second
#define mp make_pair
//#define ivorysi
using namespace std;
typedef long long int64;
int N,M;
int64 C[3005][3005],S[3005][3005],ans;
 
int64 fpow(int64 x,int64 c,int64 MOD) {
    int64 res = 1,t = x;
    while(c) {
        if(c & 1) res = res * t % MOD;
        t = t * t % MOD;
        c >>= 1;
    }
    return res;
}
int64 ways(int x) {
    int64 res = 0;
    int64 tmp2 = fpow(2,fpow(2,N - x,M - 1),M);
    int64 t = fpow(2,N - x,M);
    int64 tmp1 = 1;
    for(int j = 0 ; j <= x ; ++j) {
        res += S[x][j] * tmp1 % M * tmp2 % M;
        tmp1 = tmp1 * t % M;
        res %= M;
    }
    return res;
}
void Solve() {
    scanf("%d%d",&N,&M);
    C[0][0] = 1;
    for(int i = 1 ; i <= N ; ++i) {
        C[i][0] = 1;
        for(int j = 1 ; j <= i ; ++j) {
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % M;
        }
    }
    S[0][0] = 1;S[1][1] = 1;
    for(int i = 1 ; i <= N ; ++i) {
        S[i][0] = 1;
        for(int j = 1 ; j <= i ; ++j) {
            S[i][j] = (S[i - 1][j - 1] + S[i - 1][j] * (j + 1)% M) % M;
        }
    }
    int t = 1;
    for(int i = 0 ; i <= N ; ++i) {
        (ans += t * C[N][i] % M * ways(i) % M) %= M;
        t = 1LL * t * (M - 1) % M;
    }
    printf("%lld\n",ans);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

F - Sweet Alchemy

題解

模型轉化很是有趣,最後就變成了有n種物品,(一個點的花費是子樹的m和,價值是子樹大小),每一個能選D個,1號節點能夠選無窮個
可是……我最多也就能轉一下模型,剩下的是很是奇怪的揹包
物品種數50,物品個數,容積體積都是\(10^9\)
後來題解說是值域很是小(價值也只有50),考慮在值域上搞搞文章
咱們把價值設成\(Y\),代價設成\(X\),按照\(Y_{i} / X_{i}\)從大到小排個序
貪心確定是錯的,可是咱們考慮這麼樣的狀況,若是有一對\(p,q\)\(p <= q\),那麼若是q選了50個,p有50個還沒選,咱們顯然能夠選\(Y_{q}\)個p物品,選\(Y_{p}\)個q物品,這樣咱們的得到的價值沒變,可是花費的體積變少了
若是如今沒有這樣的狀況了,最多也就是每種物品50個,作一個容量爲50*50*50的揹包就好,表示達到這樣價值須要的最少的體積,而後剩餘的體積用來貪心放單位價值最大的
爲何是對的呢,假如只有兩種物品,都選了50個,A多了10個,B多了20個,假如這時候把B的20個全選了是最好的,然而按照上面的置換方式,若是A數量小於B的價值,那麼咱們就和選擇了的50箇中組合幾個替換掉原先選的B物品,這樣的話保證了貪心選的話,A物品剩下的部分若能選全能被選上rem

代碼

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#define MAXN 1000005
#define PLI pair<long long,int>
#define fi first
#define se second
#define mp make_pair
#define ha 99994711
#define ba 823
//#define ivorysi
using namespace std;
typedef long long int64;
int N,Lim,dis;
int64 X,D,m[55],cost[55];
int p[55],siz[55],q[125005],id[55];
int64 dp[125005],ans;
int ql,qr;
bool cmp(int a,int b) {
    return siz[a] * cost[b] > siz[b] * cost[a];
}
void update(int64 &x,int64 y) {
    x = min(x,y);
}
void Solve() {
    scanf("%d%lld%lld",&N,&X,&D);
    Lim = N * N * N;
    scanf("%d",&m[1]);
    for(int i = 2 ; i <= N ; ++i) scanf("%d%d",&m[i],&p[i]);
    for(int i = N ; i >= 1 ; --i) {
        cost[i] += m[i];siz[i]++;
        cost[p[i]] += cost[i];siz[p[i]] += siz[i];
        id[i] = i;
    }
    for(int i = 1 ; i <= Lim ; ++i) dp[i] = X + 1;
    sort(id + 1,id + N + 1,cmp);
    dis = min(N,(int)D);
    for(int k = 1 ; k <= N ; ++k) {
        int s =  siz[id[k]];int64 v = cost[id[k]];
        for(int j = 0 ; j < s ; ++j) {
            int T = min((Lim - j)/ s,dis);
            if(id[k] == 1) T = min((Lim - j) / s,N);
            int p = (Lim - j) / s;
            ql = 1,qr = 0;
            for(int i = (Lim - j) / s ; i >= 1 ; --i) {
                while(p >= 0 && i - p <= T) {
                    while(ql <= qr && dp[j + q[qr] * s] - q[qr] * v > dp[j + p * s] - p * v) --qr;      
                    q[++qr] = p;
                    --p;
                }
                while(ql <= qr && q[ql] >= i) ++ql;
                if(ql <= qr) {
                    update(dp[j + i * s],dp[j + q[ql] * s] + (i - q[ql]) * v);
                }
            }
        }
    }
    for(int i = 0 ; i <= Lim ; ++i) {
        int64 T = X - dp[i];
        if(T < 0) continue;
        int64 tmp = i;
        int num;
        for(int k = 1 ; k <= N ; ++k) {
            if(id[k] == 1) num = T;
            else num = D - dis;
            int t = min(T / cost[id[k]],(int64)num);
            tmp += 1LL * t * siz[id[k]];
            T -= t * cost[id[k]];
        }
        ans = max(ans,tmp);
    }
    printf("%lld\n",ans);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}
相關文章
相關標籤/搜索