codeforces-1461D(二分)

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章