[题解]Mail.Ru Cup 2018 Round 1 - C. Candies Distribution
【题目】
【描述】
n个小朋友排排坐吃糖糖,小朋友从左到右编号1到n。每个小朋友手上有一定数量的糖。对于第i个小朋友来说,编号比他小的小朋友中有li个小朋友拥有的糖比他多,编号比他大的小朋友中有ri个小朋友拥有的糖比他多。已知每个小朋友手上至少有1颗糖、最多有n颗糖,求一种可能的每个小朋友手上的糖的数量的情形,输出YES和一种情形;如果不存在这样的可能,则输出NO。
数据范围:1<=n<=1000,0<=li,ri<=n
【思路】
对于第i个小朋友来说,有li+ri个小朋友比他的糖多,那么给他n-(li+ri)颗糖,即使那li+ri个比他糖多的小朋友拥有的糖的个数都不相同(即糖数分别为n-(li+ri)+1,...,n),也不会出现矛盾。按照这样的思路给大家发了糖之后,验证每个小朋友左右的比他糖多的小朋友的人数是否符合li和ri。如果符合,就输出该方案;否则,不存在可能的方案。
这道题我在比赛中没想出来【还想了好久好久……】,其实当时已经想到了,这实际上就是以“有多少人比自己糖多”给小朋友分组,但当时没想清楚怎么考虑左右关系。事实上,无论最终的分糖方案是什么,“得到相同数量的糖”的小朋友的分组都是一样的,对于每个小朋友进行检查li和ri就可以了。复杂度O(n^2)。
【我的实现】
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 7 using namespace std; 8 #define MaxN 1020 9 //int L[MaxN], R[MaxN]; 10 int ans[MaxN]; 11 12 struct node 13 { 14 int L, R; 15 int Have; 16 }a[MaxN]; 17 18 int main() 19 { 20 int n; 21 int i, j; 22 int iL, iR; 23 scanf("%d", &n); 24 for(i = 1; i <= n; i++) 25 scanf("%d", &a[i].L); 26 for(i = 1; i <= n; i++) 27 scanf("%d", &a[i].R); 28 for(i = 1; i <= n; i++) 29 a[i].Have = n - a[i].L - a[i].R; 30 for(i = 1; i <= n; i++) 31 { 32 iL = 0; 33 for(j = 1; j < i; j++) 34 if(a[j].Have > a[i].Have) 35 iL++; 36 iR = 0; 37 for(j = i + 1; j <= n; j++) 38 if(a[j].Have > a[i].Have) 39 iR++; 40 if(iL != a[i].L || iR != a[i].R) 41 { 42 printf("NO\n"); 43 return 0; 44 } 45 } 46 printf("YES\n"); 47 for(i = 1; i <= n; i++) 48 printf("%d ", a[i].Have); 49 return 0; 50 }
【评测结果】