CF1461D

题意:

给一个数列。定义一种操作如下:令mid为现数列中 (最大值+最小值)/2 向下取整,将数列分为两部分,左半边为所有不超过mid的数,右半边为所有超过mid的数,选择一部分,并将令一部分删去。给若干次询问,每次问能否经过若干次(包括 0次)操作,使得最后的数列和为给定数值。

用set维护这个东西,按他的题意走

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int N=1e5+7;
ll a[N],s[N],n,m,q;
set<ll> v;
void did(ll l,ll r){
    v.insert(s[r]-s[l-1]);
    ll mid=a[l]+a[r]>>1;
    if(mid>=a[r]||mid<a[l])    return;//重复区间不下探 
    ll midpos=upper_bound(a+l,a+r+1,mid)-a-1;//找第一个大于mid的位置,减去一 
    did(l,midpos);//划分两边 
    did(midpos+1,r);
}
int main(){
    int t;cin>>t;
    while(t--){
        v.clear();
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=n;++i){
            scanf("%lld",&a[i]);
        }
        sort(a+1,a+n+1);
        for(int i=1;i<=n;++i){
            s[i]=s[i-1]+a[i];
        }
        did(1,n);
        while(m--){
            scanf("%lld",&q);
            if(v.count(q))printf("Yes
");
            else        printf("No
");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/PdrEam/p/14155742.html