【AtCoder】ARC096 C-F题解

听说日本题思维都很棒,去涨涨智商qwq

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

题解

分类瞎讨论一下就好,顺时针走,逆时针走,顺时针走再去逆时针,逆时针走再去顺时针

代码

#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)\)出解了

代码

#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物品剩下的部分若能选全能被选上

代码

#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;
}

原文地址:https://www.cnblogs.com/ivorysi/p/8984487.html

时间: 2024-11-09 11:58:24

【AtCoder】ARC096 C-F题解的相关文章

AtCoder Beginner Contest 154 题解

人生第一场 AtCoder,纪念一下 话说年后的 AtCoder 比赛怎么这么少啊(大雾 AtCoder Beginner Contest 154 题解 A - Remaining Balls We have A balls with the string S written on each of them and B balls with the string T written on each of them. From these balls, Takahashi chooses one

【题解】 AtCoder ARC 076 F - Exhausted? (霍尔定理+线段树)

题面 题目大意: 给你\(m\)张椅子,排成一行,告诉你\(n\)个人,每个人可以坐的座位为\([1,l]\bigcup[r,m]\),为了让所有人坐下,问至少还要加多少张椅子. Solution: 为什么加椅子?我们可以在最左边或最右边一直加直到人人都有座位. 首先这道题目抽象成二分图很简单,然后我们可以只要求解出人与座位的最大匹配是多少,总人数减去即可,但跑二分图最大匹配显然会超时,我们就可以往霍尔定理方面想. 然后你还需要知道一个霍尔定理推论:假设某个人的集合为\(X\),这个集合所对应的

【ATcoder】AtCoder Beginner Contest 161 题解

题目链接:AtCoder Beginner Contest 161 原版题解链接:传送门 A - ABC Swap 这题太水,直接模拟即可. 1 #include <iostream> 2 using namespace std; 3 int main() { 4 int a, b, c; 5 cin >> a >> b >> c; 6 swap(a, b); 7 swap(a, c); 8 cout << a << " &

【AtCoder】ARC082 F - Sandglass

[链接]F - Sandglass [题意]给定沙漏A和B,分别装着a和X-a的沙子,开始时A在上B在下,每秒漏1,漏完不再漏.给定n,有n个时刻ai沙漏倒转.给定m个询问,每次询问给定初值a和时刻t,求A中沙子量. [算法]数学(函数) [题解] 先不考虑时刻,令ft(a)表示沙子初值a时,当前A中的沙子数.(x轴是初值a,y轴是沙子数num) 时刻为0时,显然是一条从0出发斜率为1的直线. 若A在上,则每过1s,整段函数都下移一个单位,碰到y=0则变成平的. 若A在下,则每过1s,整段函数都

【AtCoder】ARC067 F - Yakiniku Restaurants 单调栈+矩阵差分

[题目]F - Yakiniku Restaurants [题意]给定n和m,有n个饭店和m张票,给出Ai表示从饭店i到i+1的距离,给出矩阵B(i,j)表示在第i家饭店使用票j的收益,求任选起点和终点的最大(收益-代价).n<=5000,m<=200. [算法]单调栈+矩阵差分 [题解]直接枚举区间,很难同时计算m张票,我们反过来考虑每个B(i,j)的贡献. 对于B(i,j),令x为满足x<i,B(x,j)>B(i,j)的最大的x,令y为满足y>i,B(y,j)>B(

【AtCoder】AGC005 F - Many Easy Problems 排列组合+NTT

[题目]F - Many Easy Problems [题意]给定n个点的树,定义S为大小为k的点集,则f(S)为最小的包含点集S的连通块大小,求k=1~n时的所有点集f(S)的和取模924844033.n<=2*10^5. [算法]排列组合+NTT [题解]考虑每个点只会在k个点都在其一个子树时无贡献,即: $$ANS_k=\sum_{x=1}^{n}\binom{n}{k}-\sum_{y}\binom{sz[y]}{k}+\binom{n-sz[y]}{k}$$ 令$cnt_i$表示满足s

【AtCoder】AGC023 A-F题解

可以说是第一场AGC了,做了三道题之后还有30min,杠了一下D题发现杠不出来,三题滚粗了 rating起步1300+,感觉还是很菜... 只有三题水平显然以后还会疯狂--啊(CF的惨痛经历) 改题的感觉似乎还不错因为思维都非常的妙(我根本想不到) A - Zero-Sum Ranges 开场娱乐大家的小水题,区间和为0的情况存在于sum[R] == sum[L - 1],只要记录一下某一个值的sum出现了多少次就行,懒得离散化直接用map就OK啊 代码 #include <iostream>

【AtCoder】ARC099 F - Eating Symbols Hard

题解 一道神奇的题 我们把操作S构成的A数组用一个多项式表示出来 \(t(S) = \sum_{i = -10^9}^{10^9} A_{i}X^{i}\) 如果往S前面添加一个字符的话 \(t<(S) = t(S)X^{-1}\) \(t>(S) = t(S)X\) \(t+(S) = t(S) + 1\) \(t-(S) = t(S) - 1\) 那么我们对于最终的序列求一个哈希值c,如果一段区间操作后的结果和c一样的话就有 \(t_{S_i}t_{S_{i + 1}}...t_{S_j}

AtCoder Beginner Contest 115 题解

题目链接:https://abc115.contest.atcoder.jp/ A Christmas Eve Eve Eve 题目: Time limit : 2sec / Memory limit : 1024MB Score : 100 points Problem Statement In some other world, today is December D-th. Write a program that prints Christmas if D=25, Christmas E

AtCoder Grand Contest 007题解

传送门 \(A\) 咕咕咕 //quming #include<bits/stdc++.h> #define R register #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i) #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i) #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v) template<