[构造]D. N Problems During K Days

博客围绕Polycarp编程训练问题展开,他要在k天内解决n个问题,每天至少解决1个,后一天解决问题数需满足一定条件。给出了输入输出要求,解题思路是先构造接近n的连续序列,再从尾贪心填补差值,还提及若无法填补则无解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Polycarp has to solve exactly nn 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 kk days. It means that Polycarp has exactly kk days for training!

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

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

  • sum of all aiai for ii from 11 to kk should be nn;
  • aiai should be greater than zero for each ii from 11 to kk;
  • the condition ai<ai+1≤2aiai<ai+1≤2ai should be satisfied for each ii from 11 to k−1k−1.

Your problem is to find any array aa of length kk satisfying the conditions above or say that it is impossible to do it.

Input

The first line of the input contains two integers nn and kk (1≤n≤109,1≤k≤1051≤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 aa of length kk satisfying Polycarp's rules of training, print "NO" in the first line.

Otherwise print "YES" in the first line, then print kk integers a1,a2,…,aka1,a2,…,ak in the second line, where aiai should be the number of problems Polycarp should solve during the ii-th day. If there are multiple answers, you can print any.

 题意 n个数m个空 求得一序列满足  a[i - 1] * 2 >= a[i] > a[i - 1]

解题思路, 先构造一个和最接近n的连续序列

则这个连续序列和n的差必然会小于m

然后从尾按题目要求贪心填即可, 填补了则无解

代码:

/*
    Zeolim - An AC a day keeps the bug away
*/

//pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <sstream>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
//using namespace __gnu_pbds;
//typedef tree <long long, null_type, less <long long>, rb_tree_tag, tree_order_statistics_node_update> rbtree;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 10;
const ll MOD = 1e9 + 7;

ll n, m, arr[MAXN];

bool check(ll x)
{
	return ( (x + x + n - 1) * n / ll(2) <= m);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);     cout.tie(0);
    //freopen("D://test.in", "r", stdin);
    //freopen("D://test.out", "w", stdout);
    
	cin >> m >> n;

	int fst = 1, lst = m, mid, ans = 1;

	if(!check(1))
	{
		cout << "NO\n";
		return 0;
	}

	while(fst <= lst)
	{
		mid = (fst + lst) / 2;
		if(check(mid))
			fst = mid + 1, ans = mid;
		else
			lst = mid - 1;
	}
	
	while(check(ans + 1))
		++ans;
		
	for(int i = 0; i < n; ++i)
		arr[i] = i + ans, m -= arr[i]; 


	for(int i = n - 1; i >= 0 && m; --i)
	{
		if(arr[i - 1] * 2 - arr[i] >= m)
		{
			arr[i] += m, m = 0;
			break;
		}
			
		else
		{
			m -= (arr[i - 1] * 2 - arr[i]);
			arr[i] = arr[i - 1] * 2;
		}
	}
		
	
	if(m)
	{
		cout << "NO\n";
	}
	else
	{
		cout << "YES\n";
		for(int i = 0; i < n; ++i)
			cout << arr[i] << ' ';
	}
	
		
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值