codeforces1461D-Divide and Summarize
题目链接
题目描述:
给定n个数组成的数列,选择一个mid值为当前数列中最大值与最小值之和除以二(向下取整),将这个数列分割为全部元素小于等于mid的一个数列和大于mid的另一个数列,数列内部的元素保持在原数列中的相对顺序,并舍去其中的一个数列,之后对剩下的那个数列进行上述重复操作,直至数列只剩下一个元素无法再分割。
给定m个数,分别询问这m个数是否有在分割出的数列中所有元素之和与其相等。
思路:
观察分割方法,发现数列的原顺序对结果并没有影响,所以先对数列排序,排序后开始二分寻找分割点,模拟分割的过程,通过搜索直接求出所有的分割数列和,用map记录结果,在查询时直接离线查询即可。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e5+10;
const double PI = acos(-1.0);
#define Test ll tesnum;tesnum = read();while(tesnum--)
ll read();
ll pre[N];
int a[N];
map<ll,int> mp;
int binary_search(int l, int r, int val) {
while (r - l > 1) {
int mid = (l+r)/2;
if (a[mid] <= val) {
l = mid;
}else {
r = mid;
}
}
return l;
}
void dfs(int l,int r){
if(l>r)return ;
if(l==r){
mp[a[l]]++;
return ;
}
mp[pre[r]-pre[l-1]]++;
int mid = (a[l]+a[r])/2;
int md = binary_search(l, r+1, mid);
if (md == r) return ;
dfs(l,md);
dfs(md+1,r);
}
int main() {
int t;
scanf("%d",&t);
while(t--){
int n,q;
scanf("%d%d",&n,&q);
for(int i = 1; i <= n; i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
memset(pre,0,sizeof(pre));
mp.clear();
for(int i = 1; i <= n; i++){
pre[i] = pre[i-1]+a[i];
}
dfs(1,n);
for(int i = 1; i <= q; i++){
int x;
scanf("%d",&x);
if(mp[x]){
printf("Yes
");
}else{
printf("No
");
}
}
}
return "BT7274", NULL;
}
inline ll read() {
ll hcy = 0, dia = 1;
char boluo = getchar();
while (!isdigit(boluo)) {
if (boluo == '-')dia = -1;
boluo = getchar();
}
while (isdigit(boluo)) {
hcy = hcy * 10 + boluo - '0';
boluo = getchar();
}
return hcy * dia;
}