因此到了第 u 轮,先手已经拿到了 nowa = i + (u / 2 - j) 个,后手已经拿到了 nowb = j + ((u + 1) / 2 - i) 个
如果 u 是偶数,表示当前轮为先手操作,转移方程:res = max(res, dfs(u + 1, i + 1, j) + a[nowa + 1], dfs(u + 1, i, j)) ,分别表示选自己 or ban对方
如果 u 是奇数,表示当前轮为后手操作,转移方程:res = max(res, dfs(u + 1, i, j), dfs(u + 1, i, j + 1) - b[nowb + 1]),分别表示ban对方 or 选自己
#include<iostream>#include<cstring>#include<cmath>#include<cstdio>#include<vector>#include<map>#include<algorithm>#include<queue>#include<iomanip>#include<random>#include<set>usingnamespace std;#defineintlonglongconstint N =2e5+10;int f[N][15][15];int n , k;int a[N], b[N];intdfs(int u ,int i ,int j){if(u ==2* n)return0;if(f[u][i][j]!=-1e18)return f[u][i][j];int res;int nowa = i +(u /2- j);int nowb = j +((u +1)/2- i);if(u %2==0){
res =-1e18;if(nowa + nowb <=2* n && i < k)
res =max({res ,dfs(u +1, i +1, j)+ a[nowa +1],dfs(u +1, i , j)});else res =max(res ,dfs(u +1, i , j));}else{
res =1e18;if(nowa + nowb <=2* n && j < k)
res =min({res ,dfs(u +1, i , j),dfs(u +1, i , j +1)- b[nowb +1]});else res =min(res ,dfs(u +1, i , j));}return f[u][i][j]= res;}voidAsuka(){
cin >> n >> k;for(int i =1; i <= n ; i ++)
cin >> a[i];for(int i =1; i <= n ; i ++)
cin >> b[i];sort(a +1, a +1+ n ,greater());sort(b +1, b +1+ n ,greater());for(int i =0; i <=2* n ; i ++){for(int j =0; j <= k ; j ++){for(int z =0; z <= k ; z ++){
f[i][j][z]=-1e18;}}}
cout <<dfs(0,0,0)<<"\n";return;}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);int t =1;// cin >> t;while(t --){Asuka();}return0;}
#include<bits/stdc++.h>usingnamespace std;#defineintlonglongvoidsolve(){int n; cin >> n;
vector<vector<int>>g(n +1);for(int i =1; i < n; i ++){int u, v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);}
vector<int>deep(n +1),ans(n +1);
function<void(int,int)> dfs =[&](int u,int fa){for(auto v : g[u]){if(v == fa)continue;
deep[v]= deep[u]+1;
ans[v]= deep[u]+1;dfs(v, u);
ans[u]=max(ans[u], ans[v]);}};dfs(1,-1);int res =0;for(auto v : g[1]) res += ans[v];
cout << res <<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;// cin >> t;while(t --){solve();}}
Problem D. Gambler’s Ruin(双指针)
如果赔率为 x,某个人下注 c,队伍获胜概率 p,那么他期望获得:
(
x
−
1
)
×
c
×
p
−
c
×
(
1
−
p
)
(x-1)\times c\times p-c\times (1-p)
(x−1)×c×p−c×(1−p),该式大于等于 0,可以得到
p
×
x
>
1
p\times x>1
p×x>1 时,这个人会下注
因此我们按照 p 从大到小排序,可以发现一段前缀
p
r
e
i
pre_i
prei 会下注第一个队伍获胜,一段后缀
s
u
f
j
suf_j
sufj 会下注第二个队伍获胜,设第一个队伍赔率
x
x
x,第二个队伍赔率
y
y
y,有
1
p
i
≤
y
<
1
p
i
+
1
\frac{1}{p_i}\leq y<\frac{1}{p_{i+1}}
pi1≤y<pi+11 和
1
p
j
≤
x
<
1
1
−
p
j
−
1
\frac{1}{p_{j}}\leq x<\frac{1}{1-p_{j-1}}
pj1≤x<1−pj−11
目标是让
p
r
e
i
+
s
u
f
j
−
max
(
p
r
e
i
×
x
,
s
u
f
j
×
y
)
pre_i+suf_j-\max(pre_i\times x, suf_j\times y)
prei+sufj−max(prei×x,sufj×y) 最小,所以
x
=
1
p
i
x=\frac{1}{p_i}
x=pi1
y
=
1
p
j
y=\frac{1}{p_j}
y=pj1,此时答案即为
p
r
e
i
+
s
u
f
j
−
max
(
p
r
e
i
p
i
,
s
u
f
j
1
−
p
j
)
pre_i+suf_j-\max(\frac{pre_i}{p_i},\ \frac{suf_j}{1-p_j})
prei+sufj−max(piprei,1−pjsufj)
当
i
i
i 固定时,一定会存在某个
p
p
p 使得
j
≤
p
j\leq p
j≤p 时,
p
r
e
i
p
i
≤
s
u
f
j
1
−
p
j
\frac{pre_i}{p_i}\leq\ \frac{suf_j}{1-p_j}
piprei≤1−pjsufj,答案
p
r
e
i
+
s
u
f
j
−
s
u
f
j
1
−
p
j
pre_i+suf_j-\frac{suf_j}{1-p_j}
prei+sufj−1−pjsufj,而
j
>
p
j>p
j>p 时,
p
r
e
i
p
i
>
s
u
f
j
1
−
p
j
\frac{pre_i}{p_i}>\ \frac{suf_j}{1-p_j}
piprei>1−pjsufj,答案
p
r
e
i
+
s
u
f
j
−
p
r
e
i
p
i
pre_i+suf_j-\frac{pre_i}{p_i}
prei+sufj−piprei
随着 i 增大,j 会变小,所以使用双指针
注意不要用printf输出否则会t(?
#include<bits/stdc++.h>usingnamespace std;#defineintlonglong#definedoublelongdoubletypedef pair<double,int> PDI;voidsolve(){int n; cin >> n;
vector<PDI>a(n +1),b(1);for(int i =1; i <= n; i ++) cin >> a[i].first >> a[i].second;sort(a.begin()+1, a.end(), greater<PDI>());for(int i =1; i <= n; i ++){if(i ==1||fabs(a[i].first - a[i -1].first)>1e-10) b.push_back(a[i]);else b[b.size()-1].second += a[i].second;}int m = b.size()-1;
vector<int>pre(m +1),suf(m +2);for(int i =1; i <= m; i ++) pre[i]= pre[i -1]+ b[i].second;for(int i = m; i >=1; i --) suf[i]= suf[i +1]+ b[i].second;double ans =0.0;for(int i =1, j = m; i <= m; i ++){while(j > i && pre[i]/ b[i].first > suf[j]/(1- b[j].first)) j --;
ans =max(ans, pre[i]+ suf[j +1]-1.0* pre[i]/ b[i].first);if(i >= j)break;
ans =max(ans, pre[i]+ suf[j]-1.0* suf[j]/(1- b[j].first));}
cout << fixed <<setprecision(10)<< ans <<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;// cin >> t;while(t --){solve();}}
Problem E. Hammer to Fall(根号分治)
#include<bits/stdc++.h>usingnamespace std;#defineintlonglongtypedef pair<int,int> PII;constint N =1e5;constint INF =0x3f3f3f3f3f3f3f3f;constint mod =998244353;voidsolve(){int n, m, q; cin >> n >> m >> q;
vector<int>a(n +1),ind(n +1);for(int i =1; i <= n; i ++) cin >> a[i];
vector<vector<PII>>g(n +1);for(int i =1; i <= m; i ++){int u, v, w; cin >> u >> v >> w;
g[u].push_back({v, w});
g[v].push_back({u, w});
ind[u]++; ind[v]++;}
vector<int>b(q +1);for(int i =1; i <= q; i ++) cin >> b[i];// 记录所有二类点的邻接点中的二类点int X =600;
vector<vector<PII>>big(n +1);
vector<int>dp(n +1);
vector<multiset<PII>>mst(n +1);for(int i =1; i <= n; i ++){for(auto t : g[i]){int v = t.first, w = t.second;if(ind[v]<= X)continue;
big[i].push_back({v, w});
mst[v].insert({dp[i]+ w, i});}}// 根号分治更新每个点答案auto work1 =[&](int v){int cur = dp[v];
dp[v]= INF;for(auto t : g[v]){int u = t.first, w = t.second;
dp[v]=min(dp[v], dp[u]+ w);}for(auto t : big[v]){int u = t.first, w = t.second;
mst[u].erase({cur + w, v});
mst[u].insert({dp[v]+ w, v});}};auto work2 =[&](int v){int cur = dp[v];
dp[v]=(*mst[v].begin()).first;for(auto t : big[v]){int u = t.first, w = t.second;
mst[u].erase({cur + w, v});
mst[u].insert({dp[v]+ w, v});}};for(int i = q; i >=1; i --){int v = b[i];if(ind[v]<= X)work1(v);elsework2(v);}int ans =0;for(int i =1; i <= n; i ++){
ans =(ans + dp[i]* a[i]% mod)% mod;}
cout << ans <<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;// cin >> t;while(t --){solve();}}
Problem G. Let Them Eat Cake(模拟)
暴力模拟
不想写了偷队友的码用用
#include<iostream>#include<cstring>#include<cmath>#include<cstdio>#include<vector>#include<map>#include<algorithm>#include<queue>#include<iomanip>#include<random>#include<set>usingnamespace std;constint N =1e5+10;int n;voidAsuka(){
cin >> n;
vector<int>a , b;for(int i =0; i < n ; i ++){int x;cin >> x;
a.emplace_back(x);}int res =0;bool flag =false;while(1){int cnt =0;if(!flag){if(a.size()==1)break;for(int i =0; i < a.size(); i ++){if(i !=(int)(a.size()-1)&& a[i]< a[i +1]){continue;}elseif(i !=0&& a[i]< a[i -1]){continue;}else{
b.emplace_back(a[i]);}}
a.clear();}else{if(b.size()==1)break;for(int i =0; i < b.size(); i ++){if(i !=(int)(b.size()-1)&& b[i]< b[i +1]){continue;}elseif(i !=0&& b[i]< b[i -1]){continue;}else{
a.emplace_back(b[i]);}}
b.clear();}
res ++;
flag ^=1;}
cout << res <<'\n';return;}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);int t =1;// cin >> t;while(t --){Asuka();}return0;}
Problem H. Life is Hard and Undecidable, but…(构造)
想到了横着的线没想到对角线…被题目给的例子硬控了好久
#include<bits/stdc++.h>usingnamespace std;#defineintlonglongtypedef pair<int,int> PII;voidsolve(){int k; cin >> k;
vector<PII> ans;
ans.push_back({150,150});
k --;int tmp =150;for(int i =1; i <= k; i ++){
ans.push_back({tmp - i, tmp - i});
ans.push_back({tmp + i, tmp + i});}
cout << ans.size()<<'\n';for(auto t : ans) cout << t.first <<' '<< t.second <<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;// cin >> t;while(t --){solve();}}
Problem J. Middle Race(二分)
#include<bits/stdc++.h>usingnamespace std;#defineintlonglongconstint INF =0x3f3f3f3f3f3f3f3f;voidsolve(){int n, A, B, C; cin >> n >> A >> B >> C;if(A < B)swap(A, B);if(A < C)swap(A, C);if(B < C)swap(B, C);auto cal =[&](int a,int b){return a *(A - C)+ b *(B - C)+ n * C;};int cnta =0, cntb =0, dif = INF;for(int a =0; a <= n; a ++){int l =0, r = n - a;while(l < r){int mid = l + r >>1;if(cal(a, mid)*3>=(A + B + C)* n) r = mid;else l = mid +1;}if(r >=1&&llabs(cal(a, r)*3-(A + B + C)* n)>llabs(cal(a, r -1)*3-(A + B + C)* n)) r --;if(llabs(cal(a, r)*3-(A + B + C)* n)< dif){
dif =llabs(cal(a, r)*3-(A + B + C)* n);
cnta = a, cntb = r;}}for(int i =1; i <= cnta; i ++){
cout << A << endl;int c; cin >> c >> c;}for(int i =1; i <= cntb; i ++){
cout << B << endl;int c; cin >> c >> c;}for(int i =1; i <= n - cnta - cntb; i ++){
cout << C << endl;int c; cin >> c >> c;}}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;
cin >> t;while(t --){solve();}}
Problem M. Rock-Paper-Scissors Pyramid(思维)
把遇到的字符放进栈中,每次先判断能否赢栈顶,可以就弹出栈顶继续判断,不能就直接入栈
最后答案就是栈的第一个数(不是栈顶)
#include<bits/stdc++.h>usingnamespace std;#defineintlonglongtypedef pair<char,char> PCC;voidsolve(){
string s; cin >> s;
stack<char> stk;
map<PCC,bool> mp;
mp[{'R','R'}]= mp[{'R','S'}]=1;
mp[{'S','S'}]= mp[{'S','P'}]=1;
mp[{'P','P'}]= mp[{'P','R'}]=1;for(int i =0; i < s.size(); i ++){if(i ==0) stk.push({s[i]});else{while(!stk.empty()){if(mp[{s[i], stk.top()}]) stk.pop();elsebreak;}
stk.push(s[i]);}}char ans;while(stk.size()){
ans = stk.top();
stk.pop();}
cout << ans <<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;
cin >> t;while(t --){solve();}}