打卡信奥刷题(546)用C++信奥P7107[普及组/提高] 天选之人
天选之人
题目背景
暑假期间,学校不提供午餐,Gnar 只好找伙计们一起点外卖。
尴尬的是,外卖很快送到却没人乐意去校门口拿,毕竟户外可是 35° C35\degree\!\text{C}35°C 高温!此时 Gnar 想到了好主意:“我给一人捏了一张纸团,其中一张写有记号,不如我们抓阄决定,谁抽到带记号的谁去拿!”
于是 Gnar 连续拿了六天的外卖。
这可让他不服又委屈:“换个规则!一人准备三张纸团,五张有记号,每人抽三张,记号最多的去拿!”
Gnar 紧张地展开手中的纸团,两个记号赫然映在眼前。大伙们刚想放声大笑他的非酋运气,有人缓缓举起三张纸片说道:“我也抽到了两个记号……”
题目描述
好奇的 Gnar 想研究一般情况下抽到最多记号的人数。他给参与抓阄的 nnn 人一人准备了 mmm 张捏好的纸团,一共 nmnmnm 张,其中恰好 kkk 张提前写了记号。随后每个人在均匀打乱的纸团中各抽 mmm 张。
一个人抽到最多的记号,当且仅当没有人抽到的记号比他还多。请你帮 Gnar 判断是否可能会恰好 p\boldsymbol{p}p 个人抽到最多的记号。Gnar 喜欢追根问底,所以如果有可能,你还需构造每个人抽的纸团中分别有多少带记号、有多少不带记号。
形式化地,假设第 iii 个人抽到了 xix_ixi 张带记号的纸团和 yiy_iyi 张不带记号的纸团,你的构造应满足:
- xi,yi≥0x_i, y_i \ge 0xi,yi≥0,xi+yi=mx_i + y_i = mxi+yi=m。
- ∑i=1nxi=k\displaystyle \sum_{i = 1}^{n} x_i = ki=1∑nxi=k。
- 有且仅有 p\boldsymbol{p}p 个互不相同的 jjj 使 xj=maxi=1n{xi}\displaystyle x_j = \max_{i = 1}^{n} \{x_i\}xj=i=1maxn{xi}。
输入格式
输入四个整数 n,m,k,pn, m, k, pn,m,k,p,含义详见题目描述。
输出格式
第一行输出 YES 或 NO(不区分大小写,yEs / No 均可),表示是否会恰好 ppp 个人抽到最多的记号。
如果第一行输出 YES,接下来 nnn 行每行输出 xi,yix_i, y_ixi,yi,表示每个人抽到带与不带记号的纸团个数。
因答案可能不唯一,本题采用 Special Judge,只要构造符合题面中的要求均视为正确。
样例 #1
样例输入 #1
3 3 5 2
样例输出 #1
YES
2 1
2 1
1 2
样例 #2
样例输入 #2
3 3 3 2
样例输出 #2
NO
样例 #3
样例输入 #3
3 3 5 3
样例输出 #3
NO
提示
【样例解释 #1】
样例给出了一种满足题述条件的构造。
【样例解释 #2】
不论如何,记号的分布从高到低只有三种情况:{3,0,0}\{3,0,0\}{3,0,0},{2,1,0}\{2,1,0\}{2,1,0},{1,1,1}\{1,1,1\}{1,1,1},抽到最多记号的人数分别对应 111,111,333。因此无法构造 p=2p = 2p=2 的方案。
【数据规模与约定】
本题采用捆绑测试。你必须通过 Subtask 中所有的测试点才能获得该 Subtask 的分数。
- Subtask #1 (15 points):n,m≤8n,m \le 8n,m≤8。
- Subtask #2 (15 points):n,m≤100n,m \le 100n,m≤100。
- Subtask #3 (20 points):n,m≤105n,m \le 10^5n,m≤105。
- Subtask #4 (10 points):p=1p = 1p=1。
- Subtask #5 (40 points):无特殊限制。
对于所有的数据,保证 1≤p≤n≤1051 \le p \le n \le {10}^51≤p≤n≤105,1≤m≤1091 \le m \le {10}^91≤m≤109,0≤k≤nm0 \le k \le n m0≤k≤nm。
C++实现
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
long long n, m, k, p, t, tot, tmp;
int main(){
scanf(“%lld%lld%lld%lld”, &n, &m, &k, &p);
tot = k;
t = k / p > m ? m : k / p;
tot -= t * p;
if (n == p){
if (t * p == k)
{
printf(“YES\n”);
for (int i = 1; i <= n; ++i)
printf(“%lld %lld\n”, t, m - t);
}
else
printf(“NO\n”);
}
else{
if ((n - p) * (t - 1) < tot)
printf("NO\n");
else{
printf("YES\n");
for (int i = 1; i <= p; ++i)
printf("%lld %lld\n", t, m - t);
for (int i = p + 1; i <= n; ++i)
{
if (tot < (t - 1))
printf("%lld %lld\n", tot, m - tot);
else
printf("%lld %lld\n", t - 1, m - t + 1);
tot -= t - 1;
if (tot < 0)
tot = 0;
}
}
}
return 0;
}

后续
接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容
更多推荐



所有评论(0)