洛谷月赛 P7107 天选之人

AC传送门!

题目大意

对于两个序列 \(x_i, y_i\), 使得他们满足下列条件:

  1. \(x_i, y_i \ge 0, x_i + y_i = m\)
  2. \(\sum\limits^{n}_{i=1}x_i = k\)
  3. 有且仅有 \(p\) 个互不相同的 \(j\) 使 \(x_j = \max\limits^n_{i-1} \{x_i\}\)

Solution:

直接贪心即可。首先直接 \(k / p\) 作为前 \(p\) 个的最大值,可以证明这样一定不会更劣。当然,这里也可以利用二分来判断答案是否合法,从而得到一个合法解,但没有必要。

接着,考虑如何输出剩下的解。首先,我们要保证剩下的所有 \(x\) 一定要小于 \(k / p\),所以考虑部分答案设为 \(k / p - 1\), 那么不断将 \(k\) 减去该值,如果小于,则输出不整的那一剩下部分,最后全部输出 \(0\) 即可。

代码:

#include <bits/stdc++.h>
using namespace std;
#define N 1000010
#define int long long

template <class T>  
inline void read(T& a){
    T x = 0, s = 1;
    char c = getchar();
    while(!isdigit(c)){
        if(c == '-') s = -1;
        c = getchar(); 
    }
    while(isdigit(c)){
        x = x * 10 + (c ^ '0');
        c = getchar(); 
    }
    a = x * s;
    return ; 
}

int n, m, k, p; 


signed main(){
        read(n), read(m), read(k), read(p);
        int pin = k / p;
	if(pin > m) pin = m;   // 平均值 
	if((n - p) * (pin - 1) < (k - pin * p) || (k == 0 && p != n)){
		printf("no");
		return 0; 
	}
	if(n == p && (double)n / p != n / p){
		printf("no\n");
		return 0; 
	}
	printf("yes\n");
	for(int i = 1; i <= p; i++)
		printf("%lld %lld\n", pin, m - pin);
	int cnt = 0;
	k -= p * pin; 
	while(k >= pin && cnt < n - p){
		printf("%lld %lld\n", pin - 1, m - pin + 1);
		k -= pin - 1; 
		cnt++; 
	}
	if(k != 0){
		printf("%lld %lld\n", k, m - k);
		cnt++; 
	}
	for(int i = 1; i <= n - p - cnt; i++)
		printf("0 %lld\n", m); 
	return 0;
}
posted @ 2020-11-28 21:29  雪之下,树之旁  阅读(196)  评论(0编辑  收藏  举报