据说日本题思惟都很棒,去涨涨智商qwqios
枚举买多少个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; }
分类瞎讨论一下就好,顺时针走,逆时针走,顺时针走再去逆时针,逆时针走再去顺时针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; }
容斥,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; }
模型转化很是有趣,最后就变成了有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; }