题目大意:给出$N$个数两两的和共$\frac{N \times (N-1)}{2}$个数,请你求出原来的$N$个数
输入:第一行一个数$N$,第二行$\frac{N \times (N-1)}{2}$个数表示两两之和(不保证有序)
输出:第一行为可行解个数$K$,接下来$K$行每行一个方案,每一个方案的数字从小到大输出,中间有一个空格;方案按字典序从大到小输出。
sample input:
4
3 6 5 4 5 7
sample output:
1
1 2 3 4
数据范围:$2 \leq N \leq 300,$所有$N$个数不超过$10^8$
考试的时候只拿了$N \leq 50$的$60$分不甘心$qwq$
考虑将所有和从小到大排序,设为数列$a_i$,原数列设为$k_i$,那么有$k_1+k_2=a_1,k_1+k_3=a_2$,但是不能知道$k_2+k_3$与$k_1+k_4$的大小关系。然后我们能够发现:如果我们知道$k_1$,那么可以知道$k_2$和$k_3$,然后知道$k_2+k_3$,将其从$a_i$中删掉之后就能知道$k_4$,知道$k_4$并删掉$k_2+k_4,k_3+k_4$之后又能知道$k_5$,以此类推就可以得到整个原数列,而如果其中有任何一步出现了没有在$a_i$中出现的和就表示答案非法。
于是有了$60$分想法:枚举$k_1$的取值,并用$map$维护两两之和的最小值查询与删除操作,时间复杂度为$O($值域$\times N^2logN)$
但是值域达到了$10^8绝对会TLE,于是考虑换一种枚举方式
我们从上面可以知道枚举$k_1$得到$k_2,k_3$,进而得到$k_2+k_3$,那么为什么不去枚举$k_2+k_3$得到$k_1,k_2,k_3$呢?于是考虑枚举$k_2+k_3$,又因为$k_2+k_3$最多是$a_{N+1}$,所以枚举复杂度就变成了$O(N^3logN)$,就可以$AC$此题了
如果需要常数优化可以考虑排序+二分查找或者排序+队列+懒惰堆删除,都比$map$快一些
60pts代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 inline int read(){ 5 int a = 0; 6 char c = getchar(); 7 while(!isdigit(c)) 8 c = getchar(); 9 while(isdigit(c)){ 10 a = (a << 3) + (a << 1) + (c ^ ‘0‘); 11 c = getchar(); 12 } 13 return a; 14 } 15 16 int output[12]; 17 inline void print(int x){ 18 int dirN = 0; 19 if(x == 0) 20 putchar(‘0‘); 21 else{ 22 while(x){ 23 output[dirN++] = x % 10; 24 x /= 10; 25 } 26 while(dirN--) 27 putchar(output[dirN] + 48); 28 } 29 putchar(‘ ‘); 30 } 31 32 map < int , int > m , m1; 33 vector < int > v; 34 int ans , N , now[311]; 35 36 inline void check(int dir){ 37 m1 = m; 38 now[1] = dir; 39 for(int i = 2 ; i <= N ; i++){ 40 now[i] = m1.begin()->first - dir; 41 if(now[i] > 1e8) 42 return; 43 if(!--m1.begin()->second) 44 m1.erase(m1.begin()); 45 for(int j = i - 1 ; j >= 2 ; j--) 46 if(!m1.count(now[i] + now[j])) 47 return; 48 else 49 if(!--m1.find(now[i] + now[j])->second) 50 m1.erase(m1.find(now[i] + now[j])); 51 } 52 ans++; 53 for(int i = 1 ; i <= N ; i++) 54 v.push_back(now[i]); 55 } 56 57 int main(){ 58 freopen("city.in" , "r" , stdin); 59 freopen("city.out" , "w" , stdout); 60 N = read(); 61 if(N == 1){ 62 cout << 0; 63 return 0; 64 } 65 for(int i = 1 ; i <= N * (N - 1) >> 1 ; i++){ 66 int a = read(); 67 m[a]++; 68 } 69 for(int i = m.begin()->first >> 1 ; m.begin()->first - i <= 1e8 && i ; i--) 70 check(i); 71 print(ans); 72 putchar(‘\n‘); 73 for(int i = 0 ; i < ans ; i++){ 74 for(int j = i * N ; j < (i + 1) * N ; j++) 75 print(v[j]); 76 putchar(‘\n‘); 77 } 78 return 0; 79 }
100pts代码:
1 #include<bits/stdc++.h> 2 #define M (N * (N - 1) >> 1) 3 using namespace std; 4 5 inline int read(){ 6 int a = 0; 7 char c = getchar(); 8 while(!isdigit(c)) 9 c = getchar(); 10 while(isdigit(c)){ 11 a = (a << 3) + (a << 1) + (c ^ ‘0‘); 12 c = getchar(); 13 } 14 return a; 15 } 16 17 int output[12]; 18 inline void print(int x){ 19 int dirN = 0; 20 if(x == 0) 21 putchar(‘0‘); 22 else{ 23 while(x){ 24 output[dirN++] = x % 10; 25 x /= 10; 26 } 27 while(dirN--) 28 putchar(output[dirN] + 48); 29 } 30 putchar(‘ ‘); 31 } 32 33 vector < int > v; 34 int ans , N , now[311] , num[45001]; 35 bool vis[45001]; 36 37 inline void check(int dir){ 38 if(num[1] + num[2] + num[dir] & 1) 39 return; 40 memset(vis , 0 , sizeof(vis)); 41 now[1] = (num[1] + num[2] + num[dir] >> 1) - num[dir]; 42 now[2] = (num[1] + num[2] + num[dir] >> 1) - num[2]; 43 now[3] = (num[1] + num[2] + num[dir] >> 1) - num[1]; 44 vis[1] = vis[2] = vis[dir] = 1; 45 int p = 3; 46 for(int i = 4 ; i <= N ; i++){ 47 while(vis[p]) 48 p++; 49 now[i] = num[p] - now[1]; 50 vis[p] = 1; 51 for(int j = i - 1 ; j >= 2 ; j--){ 52 int t = lower_bound(num + 1 , num + M + 1 , now[i] + now[j]) - num , q = t; 53 while(q <= M && num[t] == num[q] && vis[q]) 54 q++; 55 if(q == M + 1 || num[t] != num[q]) 56 return; 57 vis[q] = 1; 58 } 59 } 60 ans++; 61 for(int i = 1 ; i <= N ; i++) 62 v.push_back(now[i]); 63 } 64 65 int main(){ 66 freopen("city.in" , "r" , stdin); 67 freopen("city.out" , "w" , stdout); 68 N = read(); 69 if(N == 1){ 70 cout << 0; 71 return 0; 72 } 73 for(int i = 1 ; i <= M ; i++){ 74 num[i] = read(); 75 if(N == 2){ 76 print(num[i] + 1 >> 1); 77 putchar(‘\n‘); 78 for(int j = 1 ; num[i] - j >= j ; j++){ 79 print(j); 80 print(num[i] - j); 81 putchar(‘\n‘); 82 } 83 } 84 } 85 sort(num + 1 , num + M + 1); 86 for(int i = N ; i >= 3 ; i--){ 87 check(i); 88 while(i > 3 && num[i - 1] == num[i]) 89 i--; 90 } 91 print(ans); 92 putchar(‘\n‘); 93 for(int i = 0 ; i < ans ; i++){ 94 for(int j = i * N ; j < (i + 1) * N ; j++) 95 print(v[j]); 96 putchar(‘\n‘); 97 } 98 return 0; 99 }
原文地址:https://www.cnblogs.com/Itst/p/9748309.html