题目传送门
题意:
让你构造一个包括 个正整数的序列
。
这个序列满足:
(1)
(2) 。
数据范围: 。
题解:
设首项为 ,假设
成立,那么就有解。
区间的左端点由首项为 ,公差为
的等差数列求和得来。
区间的左端点由首项为 ,公比为
的等比数列求和得来。
我们可以对首项进行二分,看看能不能找到一个首项使这个序列存在。
二分的方式就是找到最大的 使
成立,然后我们就确定了首项
。
我们可以用这样的方式确定每一个数。
例如第 项确定后,我们可以把第
项看成首项,进行这样的二分操作。重复进行就好了。
最后再 构造的序列是否符合题意。
感受:
这种构造题现在来说是弱项。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e5 + 5 ;
ll n , k , a[maxn] ;
ll tn , tk ;
ll cal(ll x)
{
return k * x + k * (k - 1) / 2 ;
}
bool ok(ll x)
{
return cal(x) <= n ;
}
bool judge()
{
ll sum = a[1] ;
if(a[1] <= 0) return 0 ;
if(sum > tn) return 0 ;
for(int i = 2 ; i <= tk ; i ++)
{
sum += a[i] ;
if(sum > tn) return 0 ;
if(a[i] < a[i - 1] + 1 || a[i] > a[i - 1] * 2)
return 0 ;
}
return sum == tn ;
}
void solve(int i)
{
ll l = a[i - 1] + 1 , r = a[i - 1] * 2 ;
ll ans = l ;
if(i == 1) l = 1 , r = 1e9 ;
while(l <= r)
{
ll mid = (l + r) / 2 ;
if(ok(mid)) ans = mid , l = mid + 1 ;
else r = mid - 1 ;
}
a[i] = ans ;
n -= ans , k -- ;
}
int main()
{
int num = 0 ;
scanf("%lld%lld" , &n , &k) ;
tn = n , tk = k ;
while(k)
solve(++ num) ;
if(!judge()){printf("NO\n") ; return 0 ;}
printf("YES\n") ;
for(int i = 1 ; i <= tk ; i ++) printf("%lld " , a[i]) ;
printf("\n") ;
return 0 ;
}