HDOJ 5355 Cake 【set math】

HDOJ 5355 Cake 【set math】

題目鏈接 http://acm.hdu.edu.cn/showproblem.php?pid=5355


這個題…真的wa好多次啊…
並且對算法要求很苛刻,稍不留神就會超時
分析可以見這篇文章
http://blog.csdn.net/queuelovestack/article/details/47321211
思路就是把1~n個數分成兩份
並且使 使用二分搜索判斷的部分儘可能小 另一部分直接匹配進入分組
然後計算化簡公式即可
具體可以看我的代碼的註釋部分,還算比較詳細


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
typedef long long ll;
int T, n, m;
ll sum;
int div1, div2;
ll divSum;
ll divAve;
int divCake[15][100005];
int k;
set<int> cake;
set<int> :: iterator it;

void Resolve(){
    cake.clear();
    memset(divCake, 0, sizeof(divCake));
    sum = (1+n)*1LL*n / 2;
    if((sum % m != 0) || (n < (2*m-1))){ // sum / m ≥ n 時纔有解,結合sum的求解公式化簡得 n ≥ 2m-1
        puts("NO");
        return;
    }
    else{
        printf("YES\n");
        //如果可以分成m組, 可以將1~n分成兩組,
        //第二組div2的個數爲k*2*m (k = 0, 1, ...)
        //那麼n~(n-div2+1)這div2個數據就可以一個最大數配一個最小數分成m組和一致的數據
        //同時, 剩餘的第一組div1也要能均分成m分, 根據開始求出的公式 n ≥ 2m-1, 故div1至少要有2*m-1個數據纔可以均分
        div1 = ((n-(2*m-1)) % (2*m)) +(2*m-1); // m ≤ 10  故div1至多爲40 規模極小
        div2 = n - div1;
        k = div2 / (2*m);
        //printf("div1: %d div2: %d k: %d \n", div1, div2, k);
        divSum = (div1+1)*1LL*div1 / 2;
        divAve = divSum / m;
        for(int i = 1; i <= div1; i++) cake.insert(i);
        for(int i = 0; i < m; i++){ // 分前div1個蛋糕
            int tempAve = divAve;
            int pos = 0;
            while(tempAve > 0){
                it = cake.upper_bound(tempAve);
                //upper_bound(x) 若x存在, 返回有序數組中最後一個值爲x的元素的下一個位置
                //若x不存在, 返回x應該存在的位置, 即小於x的元素中最大的那個元素的下一個位置
                pos++;
                divCake[i][pos] = *--it;
                tempAve -= *it;
                divCake[i][0] = pos;
                cake.erase(it);
            }
        }
        int posL = div1+1, posR = n;
        for(int i = 0; i < m; i ++){
            printf("%d", divCake[i][0]+2*k);
            for(int j = divCake[i][0]; j > 0; j--){
                printf(" %d", divCake[i][j]);
            }
            for(int l = k; l > 0; l--){
                printf(" %d %d", posL++, posR--);
            }
            printf("\n");
        }
        return;
    }
}

int main(){
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        Resolve();
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章