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;
}