CF1951D.Buying Jewels-构造

link:https://codeforces.com/contest/1951/problem/D
题意:有一个人持有 n 元钱来买商品,想买恰好 k 件,你需要构造一个长度不超过 60 的序列 p1,,ps,表示每个摊位商品的价格,对方会按照 1,,s 的顺序依次访问,并且每次买尽可能多的商品。

1n,k1018


应该可以说是很有意思的题,构造题给了 s60 的条件,怎样想到直接构造长度 2 的答案?

第一次会买 n/p1 件商品,剩下 nmodp1 元钱,第二次买 nmodp1/p2 件商品,剩下 nmodp1modp2 元…
首先需要有一个感觉,纯粹的下取整和取模的序列是很难分析(也很难计算的),对这一点有了把握后再去考虑简化问题:

  • 首先 k>n 一定无解,k=n 可以直接构造
  • k<n 的情况下, p1 如果是1的话只能买 n 件商品,那么 p12,第一次至多买 n/2 件商品,剩下 nmod2 元钱,所以至多买 n/2+nmod2=n/2 件商品,因此必要条件 之一是 kn/2
  • 然后需要有一个大胆的想法,60的条件可能是有一定迷惑性的(包括一些交互题也是)
  • 用两次构造能不能构造出来,最好的情况下是第二次直接 p2=1
  • 那就希望有nmodp1=kn/p1,然后又一个尝试 n/p1=1 是否可行,这意味着 p1n2p11,此时 np1=k1,得到 p1=nk+1,代回来 2p11=2n2k+2,而条件有 2k2n/2,则 2p112n2n/2+22n2(n/2+1)+22nn2+2n
  • 所以这样就构造出来了…
#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;
}
posted @   yoshinow2001  阅读(63)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2021-04-08 [日常摸鱼]算是一些思维题-CF680D/Hamming Code
点击右上角即可分享
微信分享提示