D. Divide and Summarize
题意:给你n个数,q次询问,问你能否具有满足和为s的序列,再求其有多少种和时需要使用m i d = m a x + m i n > > 1 来寻找有多少种和。
思路:手动模拟一下有点像线段树建树的过程,那就按照线段树来写,把线段树建树的过程改动一下,求出所有可能的序列的和,然后标记
,询问的时候看看存不存就可以了。(注意要开10倍空间!!!!!)
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; typedef long long ll; ll a[N],b[N]; map<ll,ll>p,f; int le; struct node{ ll sum; } tree[N*10]; void pushup(int n) { tree[n].sum=tree[n<<1].sum+tree[n<<1|1].sum; f[tree[n].sum]=1; } void build_tree(int n, ll l,ll r) { if(l==r){ tree[n].sum=b[l]*p[b[l]]; f[tree[n].sum]=1; } else{ ll mid=(b[l]+b[r])/2; ll pos=upper_bound(b,b+le,mid)-b; ll left_node= 2*n; ll right_node=2*n+1; build_tree(left_node,l,pos-1); build_tree(right_node,pos,r); pushup(n); } } int main(){ int t; cin>>t; while(t--){ int n,q; le=0; p.clear(); f.clear(); cin>>n>>q; for(int i=0;i<n+10;i++) b[i]=a[i]=0; for(int i=0;i<(n<<2)+10;i++) tree[i].sum=0; for(int i=0; i<n; i++){ cin>>a[i]; if(p[a[i]]==0){ b[le]=a[i]; le++; } p[a[i]]++; } sort(b,b+le); build_tree(1,0,le-1); for(int i=0;i<q;i++){ int s; cin>>s; if(f[s]!=0) cout<<"YES"<<endl; else cout<<"NO"<<endl; } } }