【洛谷月赛十一月】 天选之人
很不错的一个构造题呢
!
更好的阅读体验
细节挺多的,大概在如下几点:
- 判断是 \(NO\) 的情况
- \(p = 0\) 的情况
现在我们来讨论一下,我们先让前\(P\)个人都是最大值所有者,我们计算一下他们的最大值:
ll maxx = std::min(k / p,m);
我们依据我们算出的这个最大值来讨论:
当\(p = 0\)时显然无解,因为必定会有最大值。
\(k = 0\)时,如果\(p != n\) 则无解。
如果剩下\(n - p\)个人都取他们能取到底最大值\(maxx - 1\)却仍不能将他们需要取完的\(k - maxx * p\) 则无解。
以上是无解的三种情况,我们接下来输出有解时非最大值人的答案:
ll now = k - maxx * p;
ll put = std::max(maxx - 1,(ll)0);
for(int i = p + 1;i <= n;++i){
ll should = std::min(now,put);
std::cout<<should<<" "<<m - should<<std::endl;
now -= should;
}
\(now\)是当前是剩余的有标记的纸张数量,\(should\)是这个人所需要的答案,因为不能有负数,有标记的牌最多\(k\)张,所以进行一些大小比对。
喜闻乐见的代码环节:
// code by Dix_
#include<iostream>
#include<cstdio>
#define ll long long
ll n,m,k,p;
int main(){
scanf("%lld%lld%lld%lld",&n,&m,&k,&p);
if(p == 0){
puts("NO");
return 0;
}
if(k == 0 && p != n){
puts("NO");
return 0;
}
ll maxx = std::min(k / p,m);
if((n - p) * (maxx - 1) < k - maxx * p){
puts("NO");
return 0;
}
puts("YES");
for(int i = 1;i <= p;++i)
std::cout<<maxx<<" "<<m - maxx<<std::endl;
ll now = k - maxx * p;
ll put = std::max(maxx - 1,(ll)0);
for(int i = p + 1;i <= n;++i){
ll should = std::min(now,put);
std::cout<<should<<" "<<m - should<<std::endl;
now -= should;
}
}