18.9.20模拟赛T2 城市 枚举

题目大意:给出$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 }

 

猜你喜欢

转载自www.cnblogs.com/Itst/p/9748309.html