CF1951D.Buying Jewels-构造
link:https://codeforces.com/contest/1951/problem/D
题意:有一个人持有 \(n\) 元钱来买商品,想买恰好 \(k\) 件,你需要构造一个长度不超过 \(60\) 的序列 \(p_1,\dots,p_s\),表示每个摊位商品的价格,对方会按照 \(1,\dots,s\) 的顺序依次访问,并且每次买尽可能多的商品。
\(1\leq n,k\leq 10^{18}\)
应该可以说是很有意思的题,构造题给了 \(s\leq 60\) 的条件,怎样想到直接构造长度 \(\leq 2\) 的答案?
第一次会买 \(\lfloor n/p_1\rfloor\) 件商品,剩下 \(n\bmod p_1\) 元钱,第二次买 \(\lfloor n\bmod p_1/p_2 \rfloor\) 件商品,剩下 \(n\bmod p_1\bmod p_2\) 元…
首先需要有一个感觉,纯粹的下取整和取模的序列是很难分析(也很难计算的),对这一点有了把握后再去考虑简化问题:
- 首先 \(k>n\) 一定无解,\(k=n\) 可以直接构造
- \(k<n\) 的情况下, \(p_1\) 如果是1的话只能买 \(n\) 件商品,那么 \(p_1\geq 2\),第一次至多买 \(\lfloor n/2\rfloor\) 件商品,剩下 \(n\bmod 2\) 元钱,所以至多买 \(\lfloor n/2\rfloor +n\bmod 2=\lceil n/2\rceil\) 件商品,因此必要条件 之一是 \(k\leq \lceil n/2\rceil\)
- 然后需要有一个大胆的想法,60的条件可能是有一定迷惑性的(包括一些交互题也是)
- 用两次构造能不能构造出来,最好的情况下是第二次直接 \(p_2=1\)
- 那就希望有\(n\bmod p_1=k-\lfloor n/p_1\rfloor\),然后又一个尝试 \(\lfloor n/p_1\rfloor=1\) 是否可行,这意味着 \(p_1\leq n\leq 2p_1-1\),此时 \(n-p_1=k-1\),得到 \(p_1=n-k+1\),代回来 \(2p_1-1=2n-2k+2\),而条件有 \(-2k\geq 2\lceil n/2\rceil\),则 \(2p_1-1\geq 2n-2\lceil n/2\rceil +2\geq 2n-2(n/2+1)+2\geq 2n-n-2+2\geq n\)
- 所以这样就构造出来了…
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
int main(){
fastio;
int tc;cin>>tc;
while(tc--){
ll n,k;
cin>>n>>k;
if(k>n)cout<<"NO"<<endl;
else if(k==n){
cout<<"YES"<<endl;
cout<<1<<endl<<1<<endl;
}else if(k<=(n+1)/2){
cout<<"YES"<<endl;
cout<<2<<endl;
cout<<n-k+1<<' '<<1<<endl;
}else cout<<"NO"<<endl;
}
return 0;
}