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\n");
}else{
printf("No\n");
}
}
}
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;
}