[Algorithms]Constructive Algorithm构造算法
构造算法是什么
It's an algorithm which builds something. A graph, an array, a matrix etc. It's what test generators use to build test cases.
就是数学中的proof,
constrcutive proof:具体地给出某一对象或者能给出某一对象的计算方法
Non-constructive proof :证明的过程中,不举例而只证明语句是否正确。通常使用反正法
Example:
CF1157D N Problems During K Days
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.
题意:
构造一个数列an,使∑an= n,1<=i <=k,0<ai<ai+1≤2ai
分析:
该数列在有上下界约束条件下单调递增,
下界:公差为1的等差数列求和
上界:公比为2的等比数列求和
对每个ai,,,ak的子数列首项(即当前ai)采取greedy,取当前上下界约束条件下的最大值(使当前子数列达到最优解,尽可能多)。
注:求满足上界约束的ai时要上取整,下取整会达不到上界
排除情况:
不满足下界约束:子数列之和下界大于当前n
#include<iostream> #include<cmath> using namespace std; long long a[110000]; long long sum(long long m) { return m*(m+1)/2; } int main() { int n,k; cin>>n>>k; for(int i=1;i<=k;i++) { long long ans=max((int)(a[i-1]+1),(int)ceil((double)n/(double)(pow(2.0,k+1-i)-1)));//约束条件下的greedy if(sum(ans-i+k)-sum(ans-1)>n)//下界约束情况排除 { cout<<"NO"<<endl; return 0; } a[i]=ans; n-=ans;//更新当前n } cout<<"YES"<<endl; for(int i=1;i<=k;i++) { cout<<a[i]<<" "; } return 0; }