Codeforces Round 1043 (Div. 3) E. Arithmetics Competition
E.算术比赛
每次测试的时间限制:3 秒
每次测试内存限制:256 兆字节
输入:标准输入
输出:标准输出
E.算术竞赛 每次测试的时间限制:3 秒 每次测试的内存限制:256 兆字节3 秒 每次测试内存限制:256 兆字节 输入:标准输入 输出:标准输出
在算术比赛中,参赛者需要用手中的纸牌算出尽可能高的总和。在 "fst_ezik "队中,瓦迪姆有 nnn 张数字为 aia_iai 的牌,科斯佳有 mmm 张数字为 bib_ibi 的牌。在每一轮 qqq 比赛中,他们都想获胜,但这次的比赛规则与往常略有不同。
在每一轮比赛中,参赛者都会得到三个数字 xix_ixi 、 yiy_iyi 和 ziz_izi 。fst_ezik "队必须从他们所有的牌中准确选出 ziz_izi 张牌,但 Vadim 从他的牌组中选出的牌不能超过 xix_ixi 张,Kostya 从他的牌组中选出的牌不能超过 yiy_iyi 张。请帮助他们找出每轮 qqq 的最高和。
在算术比赛中,参赛者需要从他们手中的牌中找出尽可能高的和。在 "fst\_ezik "队中,瓦迪姆有 nnn 张数字为 a_ia\_ia_i 的牌,科斯佳有 mmm 张数字为 b_ib\_ib_i 的牌。在每一轮的 qqq 比赛中,他们都想获胜,但这次的比赛规则与往常略有不同。在每一轮比赛中,参赛者都会得到三个数字 x_ix\_ix_i 、 y_iy\_iy_i 和 z_iz\_iz_i 。fst\_ezik "队必须从他们所有的牌中准确地选出 z_iz\_iz_i 张牌,但是瓦迪姆从他的牌组中选出的牌不能超过 x_ix\_ix_i 张,而科斯佳从他的牌组中选出的牌不能超过 y_iy\_iy_i 张。请帮助他们找出每轮 qqq 的最高和。
输入
每个测试由多个测试用例组成。第一行包含一个整数 ttt - 测试用例数。 (1≤t≤104)(1 \le t \le 10^4)(1≤t≤104) - 测试用例的数量。测试用例说明如下。
每个测试用例的第一行都包含三个整数 nnn 、 mmm 、 qqq (1≤n,m≤2⋅105,1≤q≤105)(1 \le n, m \le 2 \cdot 10^5, 1 \le q \le 10^5)(1≤n,m≤2⋅105,1≤q≤105) - 瓦迪姆拥有的纸牌数量、科斯佳拥有的纸牌数量以及比赛的轮数。
第二行包含 nnn 个整数 aia_iai - 瓦迪姆牌上的数字 (1≤ai≤109)(1 \le a_i \le 10^9)(1≤ai≤109) 。
第三行包含 mmm 个整数 bib_ibi - 科斯蒂亚牌上的数字 (1≤bi≤109)(1 \le b_i \le 10^9)(1≤bi≤109) 。
接下来的 qqq 行用三个整数 xix_ixi 、 yiy_iyi 、 ziz_izi 来描述轮次。 (0≤xi≤n,0≤yi≤m,0≤zi≤xi+yi)(0 \le x_i \le n, 0 \le y_i \le m, 0 \le z_i \le x_i + y_i)(0≤xi≤n,0≤yi≤m,0≤zi≤xi+yi) - 瓦迪姆可以选择的牌的数量限制,科斯佳可以选择的牌的数量限制,以及他们需要一起选择的牌的数量。
保证所有测试用例中 nnn 的总和不超过 2⋅1052 \cdot 10^52⋅105 ,所有测试用例中 mmm 的总和不超过 2⋅1052 \cdot 10^52⋅105 ,所有测试用例中 qqq 的总和不超过 10510^5105 。
输出
对于每个测试用例,输出 qqq 个数字–相应回合的最高可能总和。
-
解决办法
- 1、他是要求我们在给定x,y,z情况下求在a个数下于x,在b个数小于y,总共z情况下,我们考虑因为要去最大值,所以我们要先要a、b都从大到小排序,接着suma、sumb前缀和算出来,那么我假设以a来枚举,那么a的枚举区间为[max(z−y,0),min(z,a)][max(z-y,0),min(z,a)][max(z−y,0),min(z,a)]。
- 2、但我们想如果从for枚举那么时间复杂度就趋近于O(n∗n)O(n*n)O(n∗n),肯定会超时,最好是在O(n∗logn)O(n*logn)O(n∗logn)
- 时最好,lognlognlogn不就是二分吗,而且二分去求最大值,但关键在于suma[mid]+sumb[z−mid]suma[mid]+sumb[z-mid]suma[mid]+sumb[z−mid]并不是单调函数,他是有单峰的,难道就没有其它办法吗。
- 3、no! 二分不行,我们可以用三分,三分就是去找单峰的,时间复杂度O(2log3n)O(2log3n)O(2log3n)不超,刚刚好。
-
欣赏(蒻蒻)代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
multiset<int>s1,s2;
multiset<int>::reverse_iterator it;
const int N=2e5+5;
int n,m,q,suma[N],sumb[N];
int qiu(int x,int g)
{int sum=0;sum+=suma[x];sum+=sumb[g-x];return sum;
}
signed main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int _,a,b,x,y,z;cin>>_;while(_--){cin>>n>>m>>q;s1.clear();s2.clear();for(int i=1;i<=n;i++){cin>>a;s1.insert(a);}for(int i=1;i<=m;i++){cin>>a;s2.insert(a);}int js=0;// cout<<"-----------------"<<'\n';for(it=s1.rbegin();it!=s1.rend();it++)++js,suma[js]=suma[js-1]+*it;// cout<<suma[js]<<" "<<*it<<'\n';js=0;// cout<<"-----------------"<<'\n';for(it=s2.rbegin();it!=s2.rend();it++)++js,sumb[js]=sumb[js-1]+*it;// cout<<sumb[js]<<" "<<*it<<'\n';// cout<<"---------------"<<'\n';for(int i=1;i<=q;i++){cin>>x>>y>>z;if(z>=n+m){cout<<suma[x]+sumb[y]<<'\n';continue;}int l=max(z-y,0ll);int r=min(x,z);while(r-l>=3){int mid1=(2*l+r)/3;int mid2=(l+2*r)/3;if(qiu(mid1,z)<=qiu(mid2,z))l=mid1;elser=mid2;}int ans=0;for(int j=l;j<=r;j++)ans=max(ans,qiu(j,z));cout<<ans<<'\n';}// cout<<"-------"<<suma[n]<<" "<<sumb[m]<<'\n';}return 0;
}