CF1951D.Buying Jewels-構造

yoshinow2001發表於2024-04-08

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

相關文章