codeforces 1157 D. N Problems During K Days (二分+构造)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhao5502169/article/details/89602549

D. N Problems During K Days
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Polycarp has to solve exactly n problems to improve his programming skill before an important programming competition. But this competition will be held very soon, most precisely, it will start in k days. It means that Polycarp has exactly k days for training!

Polycarp doesn’t want to procrastinate, so he wants to solve at least one problem during each of k days. He also doesn’t want to overwork, so if he solves x problems during some day, he should solve no more than 2x problems during the next day. And, at last, he wants to improve his skill, so if he solves x problems during some day, he should solve at least x+1 problem during the next day.

More formally: let [a1,a2,…,ak] be the array of numbers of problems solved by Polycarp. The i-th element of this array is the number of problems Polycarp solves during the i-th day of his training. Then the following conditions must be satisfied:

sum of all ai for i from 1 to k should be n;
ai should be greater than zero for each i from 1 to k;
the condition ai<ai+1≤2ai should be satisfied for each i from 1 to k−1.
Your problem is to find any array a of length k satisfying the conditions above or say that it is impossible to do it.

Input
The first line of the input contains two integers n and k (1≤n≤109,1≤k≤105) — the number of problems Polycarp wants to solve and the number of days Polycarp wants to train.

Output
If it is impossible to find any array a of length k satisfying Polycarp’s rules of training, print “NO” in the first line.

Otherwise print “YES” in the first line, then print k integers a1,a2,…,ak in the second line, where ai should be the number of problems Polycarp should solve during the i-th day. If there are multiple answers, you can print any.

昨天div3 的D题,题目很简单,题意:给你一个N,和长度为K的数组,数组要符合a[i] < a[i+1] < 2*a[i],请你输出任意一个数组和为N的数组。
这个题要注意起点即a[1]可以不是1。
思路:首先想到序列最小和肯定是a[1],a[1]+1,a[1]+2,…等差数列,最大和肯定是等比数列,如果知道他的起点的数,我们就能得到最小最大的和。所以我们可以二分一下起点就可以了。然后从后面往前补就行了,就是当前这个数能够到达的最大的数是前一个数的二倍。
注意这里有个坑点,如果K大于一定的数,那么起点一定是1,我这里是K>32的时候。
代码如下:

#include<bits/stdc++.h>

using namespace std;
const int MAX = 1e5+10;
typedef long long ll;
ll a[MAX];
ll N,K;
ll sumMin(ll x){
    ll l = x,r = x+K-1;
    ll sum = (l+r)*K/2;
    return sum;
}
ll sumMax(ll x){
    ll q = 2;
    ll sum = x*(1-pow(q,K))/(1-q);
    return sum;
}
void solve(ll Begin){
    if(sumMin(Begin) > N){
        printf("NO\n");
        return;
    }
    ll p = Begin;
    for(int i=1;i<=K;++i)
        a[i] = p++;
    ll need = N-sumMin(Begin);
    bool isok,isfind;
    if(need == 0)
        isok = true;
    else
        isok = false;
    do{
        isfind = false;
        for(int i=K;i>=2;--i){
            ll add = 2*a[i-1]-a[i];
            if(add != 0){
                isfind = true;
                if(need > add){
                    need -= add;
                    a[i] += add;
                }
                else{
                    a[i] += need;
                    need = 0;
                    isok = true;
                    break;
                }
            }
        }
    }while(isfind&&!isok);
    if(isok){
        printf("YES\n");
        for(int i=1;i<=K;++i)
            printf("%lld%c",a[i],i==K?'\n':' ');
    }
    else{
        solve(Begin+1);
        //如果当前这个数不可以,继续下一个数。
    }
}
int main(void){
    scanf("%lld%lld",&N,&K);
    ll Begin;
    //如果K > 32,sumMax会爆longlong,这里直接特判就行了。
    if(K >= 32){
        Begin = 1;
    }
    else{
        ll l = 1,r = N;
        while(r - l > 1){
            ll mid = (l+r)/2;
            if(sumMax(mid) < N){
                l = mid;
            }
            else
                r = mid;
        }
        Begin = l;
        if(sumMax(Begin) < N)
            Begin++;
        }

    solve(Begin);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhao5502169/article/details/89602549