2017中国大学生程序设计竞赛-哈尔滨站 Solution

A - Palindrome

题意:给出一个字符串,找出其中有多少个子串满足one-half-palindromic 的定义

思路:其实就是找一个i, j  使得 以i为中轴的回文串长度和以j为中轴的回文串长度都大于j - i + 1

先Manacher 预处理出以每个字符为中轴的最长回文串长度,然后用树状数组维护j ,枚举i

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 const int maxn = 5e5 + 10;
 7 
 8 int l;
 9 char Ma[maxn << 1];
10 int Mp[maxn << 1];
11 
12 inline void Manacher(char s[], int len)
13 {
14     l = 0;
15     Ma[l++] = '$';
16     Ma[l++] = '#';
17     for(int i = 0; i < len; ++i)
18     {
19         Ma[l++] = s[i];
20         Ma[l++] = '#';
21     }
22     Ma[l] = 0;
23     int mx = 0, id = 0;
24     for(int i = 0; i < l; ++i)
25     {
26         Mp[i] = mx > i ? min(Mp[2 * id - i], mx - i) : 1;
27         while(Ma[i + Mp[i]] == Ma[i - Mp[i]]) Mp[i]++;
28         if(i + Mp[i] > mx)
29         {
30             mx = i + Mp[i];
31             id = i;
32         }
33     }
34 }
35 
36 int cnt[maxn << 1];
37 char str[maxn];
38 int a[maxn];
39 int len;
40 
41 vector <int> vv[maxn];
42 
43 inline int lowbit(int x)
44 {
45     return x & (-x);
46 }
47 
48 inline void update(int x, int val)
49 {
50     for (int i = x; i <= len; i += lowbit(i))
51         a[i] += val;
52 }
53 
54 inline int query(int x)
55 {
56     int res = 0;
57     for (int i = x; i > 0; i -= lowbit(i))
58         res += a[i];
59     return res;
60 }
61 
62 int main()
63 {
64     int t;
65     scanf("%d", &t);
66     while(t--)
67     {
68         memset(a, 0, sizeof a);
69         scanf("%s", str);
70         len = strlen(str);
71         Manacher(str, len);
72         ll ans = 0;
73         int pos = 1;
74         for(int i = 2 ; i < l; i += 2)
75         {
76             cnt[pos]= Mp[i] / 2 - 1;
77             vv[pos - cnt[pos]].push_back(pos);
78             pos++;
79         }
80         for(int i = 1; i <= pos; ++i)
81         {
82             for (auto it : vv[i])
83             {
84                 update(it, 1);
85             }
86             vv[i].clear();
87             ans += query(i + cnt[i]) - query(i);
88 //            cout << ans << endl;
89         }
90         printf("%lld\n",ans);
91     }
92     return 0;
93 }
View Code

 

B - K-th Number

题意:给出n个数,把这n个数中长度>= k 的区间中的第k小的数放到数组b中,最后求出数组b中的第m大的数

思路:二分答案,然后双指针法判断是否正确,因为存在这样一个性质,假如一个长度>=k的区间里面的第k小的数 >= ans

那么 之后如果加入的数大于它,那么没有影响,如果小于它,要被计数

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 const int maxn = 1e5 + 10;
 7 
 8 int n, k ;
 9 ll m;
10 int arr[maxn];
11 int brr[maxn];
12 
13 inline bool check(int mid)
14 {
15     ll tot = 0;
16     ll res = 0;
17     for(int i = 1, j = 0; i <= n; ++i)
18     {
19         while(j <= n && res < k)
20         {
21             if(arr[++j] >= mid) ++res;
22         }
23         if(res >= k) tot += n - j + 1;
24         if(arr[i] >= mid) res--;
25     }
26     return tot >= m;
27 }
28 
29 int main()
30 {
31     int t;
32     scanf("%d", &t);
33     while(t--)
34     {
35         scanf("%d %d %lld", &n, &k, &m);
36         for(int i = 1; i <= n; ++i)
37         {
38             scanf("%d", arr + i);
39             brr[i] = arr[i];
40         }
41         sort(brr + 1, brr + 1 + n);
42         int l = 1;
43         int r = n;
44         int ans = 0;
45         while(r - l >= 0)
46         {
47             int mid = (l + r) >> 1;
48             if(check(brr[mid]))
49             {
50                 ans = mid;
51                 l = mid + 1;
52             }
53             else
54             {
55                 r = mid - 1;
56             }
57         }
58         printf("%d\n",brr[ans]);
59     }
60     return 0;
61 }
View Code

 

C - Confliction

留坑。

 

D - X-Men

题意:有若干个X-Man  他们要汇合,直到所有Xman的距离都小于等于1的时候,他们就停止行动,一个小时行进一个单位长度,求他们期望的行进时间

思路:因为给的是一棵树,实际上就是最远的两个X-man 的距离 / 2

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define N 1010
  5 
  6 struct Edge
  7 {
  8     int to, nx;
  9     inline Edge() {}
 10     inline Edge(int to, int nx) : to(to), nx(nx) {}
 11 }edge[N << 1];
 12 
 13 int t, n, m;
 14 int head[N], pos;
 15 bool vis[N];
 16 
 17 inline void Init()
 18 {
 19     memset(vis, false, sizeof vis);
 20     memset(head, -1, sizeof head);
 21     pos = 0;
 22 }
 23 
 24 inline void addedge(int u, int v)
 25 {
 26     edge[++pos] = Edge(v, head[u]); head[u] = pos;
 27     edge[++pos] = Edge(u, head[v]); head[v] = pos;
 28 }
 29 
 30 int rmq[N << 1];
 31 int F[N << 1];
 32 int P[N], deep[N];
 33 int cnt;
 34 
 35 struct ST
 36 {
 37     int mm[N << 1];
 38     int dp[N << 1][20];
 39     inline void init(int n)
 40     {
 41         mm[0] = -1; 
 42         for (int i = 1; i <= n; ++i)
 43         {
 44             mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1];
 45             dp[i][0] = i;
 46         }
 47         for (int j = 1; j <= mm[n]; ++j)
 48             for (int i = 1; i + (1 << j) - 1 <= n; ++i)
 49                 dp[i][j] = rmq[dp[i][j - 1]] < rmq[dp[i + (1 << (j - 1))][j - 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1];
 50     }
 51     inline int query(int a, int b)
 52     {
 53         if (a > b) swap(a, b); 
 54         int k = mm[b - a + 1]; 
 55         return rmq[dp[a][k]] <= rmq[dp[b - (1 << k) + 1][k]] ? dp[a][k] : dp[b - (1 << k) + 1][k];
 56     }
 57 }st;
 58 
 59 inline void DFS(int u, int pre)
 60 {
 61     F[++cnt] = u;
 62     rmq[cnt] = deep[u]; 
 63     P[u] = cnt;
 64     for (int it = head[u]; ~it; it = edge[it].nx)
 65     {
 66         int v = edge[it].to;
 67         if (v == pre) continue;
 68         deep[v] = deep[u] + 1;
 69         DFS(v, u);
 70         F[++cnt] = u;
 71         rmq[cnt] = deep[u];
 72     }
 73 }
 74 
 75 inline void LCA_Init(int root, int node_num)
 76 {
 77     cnt = 0; deep[1] = 0;
 78     DFS(root, root);
 79     st.init(2 * node_num - 1);
 80 
 81 }
 82 
 83 inline int query_lca(int u, int v)
 84 {
 85     return F[st.query(P[u], P[v])];
 86 }
 87 
 88 inline void Run()
 89 {
 90     scanf("%d", &t);
 91     while (t--)
 92     {
 93         scanf("%d%d", &n, &m); Init();
 94         for (int i = 1, x; i <= m; ++i)
 95         {
 96             scanf("%d", &x);
 97             vis[x] = true;
 98         }
 99         for (int i = 1, u, v; i < n; ++i)
100         {
101             scanf("%d%d", &u, &v);
102             addedge(u, v);
103         }
104         LCA_Init(1, n);
105         int ans = 0;
106         for (int i = 1; i <= n; ++i)
107         {
108             if (!vis[i]) continue;
109             for (int j = 1; j <= n; ++j)
110             {
111                 if (!vis[j] || j == i) continue;
112                 int lca = query_lca(i, j);
113                 //printf("%d %d %d\n", i, j, lca);
114                 ans = max(ans, deep[i] + deep[j] - 2 * deep[lca]);
115             }
116         }
117         printf("%d.00\n", ans / 2);
118     }
119 }
120 
121 int main()
122 {
123     #ifdef LOCAL
124         freopen("Test.in", "r", stdin);
125     #endif
126 
127     Run();
128     
129     return 0;
130 }
View Code

 

 

E - Square Network

留坑。

 

F - Permutation

题意:给出一个n,里面有1-n,构造一个数列使得满足题目要求

思路:142536  类似这样构造

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define N 100010
 6 
 7 int t, n;
 8 int arr[N];
 9 
10 int main()
11 {
12     scanf("%d", &t);
13     while (t--)
14     {
15         scanf("%d", &n);
16         int cnt = 1;
17         for (int i = 1; i <= n; i += 2)
18             arr[i] = cnt++;
19         for (int i = 2; i <= n; i += 2)
20             arr[i] = cnt++;
21         for (int i = 1; i <= n; ++i) printf("%d%c", arr[i], " \n"[i == n]);
22     }
23     return 0;
24 }
View Code

 

 

G - Debug

留坑。

 

H - A Simple Stone Game

题意:有n堆石子,每次可以移动一个石子要另一堆,如果某一次移动之后,每一堆的石子个数都是x(x > 1) 的倍数,那么游戏结束,问最少需要移动多少个石子使得游戏结束

思路:x一定是石子和的因数,我们可以枚举石子和的每个因数,求出每个因数下的移动次数,取min。至于如何求移动次数,我们可以将每个石子的余数记录下来,并将余数相加再除以因数,可以的到有多少堆石子得到石子,然后再将需要减少的石子数相加就可以得到。注意当只有一个石子的时候为0;

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 const ll INFLL = 0x3f3f3f3f3f3f3f3f;
 7 const int maxn = 1e5 + 10;
 8 
 9 int n;
10 ll arr[maxn];
11 ll sum;
12 ll ans;
13 int cnt;
14 ll brr[maxn];
15 ll crr[maxn];
16 
17 int tot;
18 ll prime[maxn];
19 bool isprime[maxn];
20 
21 inline void Init_prime()
22 {
23     memset(isprime, true, sizeof isprime);
24     isprime[0] = isprime[1] = false;
25     for(int i = 2; i < maxn; ++i)
26     {
27         if(isprime[i] == true)
28         {
29             prime[tot++] = i;
30             for(int j = i << 1; j < maxn; j += i)
31             {
32                 isprime[j] = false;
33             }
34         }
35     }
36 }
37 
38 inline void cal(ll x)
39 {
40     ll sum_tmp = 0;
41     int pos = 0;
42     for(int i = 1; i <= n; ++i)
43     {
44         if(arr[i] % x)
45         {
46             crr[pos++] = arr[i] % x;
47             sum_tmp += arr[i] % x;
48         }
49     }
50     ll p = sum_tmp / x;
51     sort(crr, crr + pos);
52     ll res = 0;
53     for(int i = 0; i < pos - p; ++i)
54     {
55         res += crr[i];
56     }
57     ans = min(ans, res);
58 }
59 
60 inline void get_x(ll tmp)
61 {
62     ll tmp_ = sqrt(tmp) + 1;
63     for(int i = 0; i < tot && prime[i] <= tmp_; ++i)
64     {
65         if(tmp % prime[i] == 0)
66         {
67             cal(prime[i]);
68         }
69     }
70 }
71 
72 int main()
73 {
74     Init_prime();
75     int t;
76     scanf("%d",&t);
77     while(t--)
78     {
79         scanf("%d", &n);
80         sum = 0;
81         for(int i = 1; i <= n; ++i)
82         {
83             scanf("%lld", arr + i);
84             sum += arr[i];
85         }
86         ans = INFLL;
87         get_x(sum);
88         cal(sum);
89         printf("%lld\n", ans);
90         
91     }
92     return 0;
93 }
View Code

 

I - Cow`s Segment
留坑。
 
J - Interview
留坑。
 
K - Server
题意:给出一些区间,每个区间附加两个值ai 和 bi  选出一些区间覆盖1 - t  并且 sgm(ai) / sgm(bi) 最小
思路:二分答案 那么 就是使得 sgm(ai) - sgm(bi) * x >0
然后 ai - bi * x > 0 的都选,,剩下的就是用最小代价覆盖所有区间 dp + 数据结构
我是用线段树和树状数组,本来以为动态开点线段树会比普通线段树要快一点,实际上没有
线段树
  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <iostream>
  4 using namespace std;  
  5 
  6 #define N 100010
  7 #define ll long long
  8 #define INF 0x3f3f3f3f
  9 
 10 const double eps = 1e-4;
 11 
 12 struct node
 13 {
 14     int l, r;
 15     double Min;
 16     inline node() {}
 17     inline node(int l, int r, double Min) : l(l), r(r), Min(Min) {}
 18 }tree[N << 2];
 19 
 20 int cnt, root;
 21 
 22 inline void Init()
 23 {
 24     cnt = 1; root = 1;
 25     tree[1] = node(0, 0, INF * 1.0); 
 26 }
 27 
 28 inline void update(int &id, int l, int r, int ql, int qr, double val) 
 29 {
 30     if (id == 0)
 31     {
 32         id = ++cnt;  
 33         tree[id] = node(0, 0, val);
 34     }
 35     if (l >= ql && r <= qr)
 36     {
 37         tree[id].Min = min(tree[id].Min, val);  
 38         return;
 39     }
 40     int mid = (l + r) >> 1;
 41     if (ql <= mid) update(tree[id].l, l, mid, ql, qr, val);
 42     if (qr > mid) update(tree[id].r, mid + 1, r, ql, qr, val);
 43 }
 44 
 45 double ansMin; 
 46 
 47 inline void query(int id, int l, int r, int pos)
 48 {
 49     if (id == 0) return;
 50     ansMin = min(ansMin, tree[id].Min); 
 51     if (l == r)
 52         return;
 53     int mid = (l + r) >> 1;
 54     if (pos <= mid) query(tree[id].l, l, mid, pos); 
 55     else query(tree[id].r, mid + 1, r, pos);
 56 }
 57 
 58 struct Interval
 59 {
 60     int l, r; double a, b;
 61     inline void scan()
 62     {
 63         scanf("%d%d%lf%lf", &l, &r, &a, &b);
 64     }
 65     inline bool operator < (const Interval &r) const 
 66     {
 67         return l < r.l;
 68     }
 69 }interval[N];
 70 
 71 int T;
 72 int n, t;
 73 
 74 inline bool check(double x)
 75 {
 76     double sum = 0.0;
 77     for (int i = 1; i <= n; ++i)
 78         if (interval[i].a - interval[i].b * x < 0)
 79             sum += interval[i].a - interval[i].b * x;
 80     Init();
 81     update(root, 0, t, 0, 0, 0.0);
 82     for (int i = 1; i <= n; ++i)
 83     {
 84         ansMin = INF * 1.0; query(root, 0, t, interval[i].l - 1);
 85         ansMin = max(ansMin, ansMin + interval[i].a - interval[i].b * x);
 86         update(root, 0, t, interval[i].l, interval[i].r, ansMin);
 87     }
 88     ansMin = INF * 1.0; query(root, 0, t, t); 
 89     return sum + ansMin > 0;  
 90 }
 91 
 92 inline void Run()
 93 {
 94     scanf("%d", &T);
 95     while (T--)
 96     {
 97         scanf("%d%d", &n, &t); 
 98         for (int i = 1; i <= n; ++i)
 99             interval[i].scan();
100         sort(interval + 1, interval + 1 + n);
101         double l = 0, r = 1000 * 1.0;
102         while (r - l > eps)
103         {
104             double mid = (l + r) / 2;
105             if (check(mid))
106                 l = mid;
107             else
108                 r = mid;
109         }
110         printf("%.3f\n", l);
111     }
112 }
113 
114 int main()
115 {
116     #ifdef LOCAL
117         freopen("Test.in", "r", stdin);
118     #endif
119 
120     Run();
121     
122     return 0;
123 }
View Code

树状数组

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 using namespace std;  
 5 
 6 #define N 100010
 7 #define ll long long
 8 #define INF 0x3f3f3f3f
 9 
10 const double eps = 1e-4;
11 
12 double a[N];
13 int T, n, t;
14 
15 inline int lowbit(int x)
16 {
17     return x & (-x);
18 }
19 
20 inline void update(int x, double val)
21 {
22     for (int i = x; i > 0; i -= lowbit(i))
23         a[i] = min(a[i], val);
24 }
25 
26 inline double query(int x)
27 {
28     if (x == 0) return 0;
29     double res = INF;
30     for (int i = x; i <= t; i += lowbit(i))
31         res = min(a[i], res);
32     return res;
33 }
34 
35 struct Interval
36 {
37     int l, r; double a, b;
38     inline void scan()
39     {
40         scanf("%d%d%lf%lf", &l, &r, &a, &b);
41     }
42     inline bool operator < (const Interval &r) const 
43     {
44         return l < r.l;
45     }
46 }interval[N];
47 
48 inline bool check(double mid)
49 {
50     double sum = 0.0;
51     for (int i = 1; i <= n; ++i)
52         if (interval[i].a - interval[i].b * mid < 0)
53             sum += interval[i].a - interval[i].b * mid;
54     for (int i = 0; i <= t; ++i) a[i] = INF;
55     for (int i = 1; i <= n; ++i)
56     {
57         double x = query(interval[i].l - 1);
58         x = max(x, interval[i].a - interval[i].b * mid);
59         update(interval[i].r, x); 
60     }
61     return sum + query(t) > 0;
62 }
63 
64 inline void Run()
65 {
66     scanf("%d", &T);
67     while (T--)
68     {
69         scanf("%d%d", &n, &t); 
70         for (int i = 1; i <= n; ++i)
71             interval[i].scan();
72         sort(interval + 1, interval + 1 + n);
73         double l = 0, r = 1000 * 1.0;
74         while (r - l > eps)
75         {
76             double mid = (l + r) / 2;
77             if (check(mid))
78                 l = mid;
79             else
80                 r = mid;
81         }
82         printf("%.3f\n", l);
83     }
84 }
85 
86 int main()
87 {
88     #ifdef LOCAL
89         freopen("Test.in", "r", stdin);
90     #endif
91 
92     Run();
93     
94     return 0;
95 }
View Code

 

 
 
L - Color a Tree
题意:给出两条规则: A , 以x为根的子树下的黑点数量不小于y  B : 除了以x为根的子树下的黑点数量不小于y ,求满足给出的所有规则,需要染色的最小数量
思路:假如我们知道答案,那么B规则就可以转变为以x为根的子树下的黑点数量不大于(ans - y)
然后二分,DFScheck
  1 #include <bits/stdc++.h>
  2 using namespace std; 
  3 
  4 #define N 100010
  5 
  6 struct Edge
  7 {
  8     int to, nx;
  9     inline Edge() {}
 10     inline Edge(int to, int nx) : to(to), nx(nx) {}
 11 }edge[N << 1];
 12 
 13 int n;
 14 int head[N], pos;
 15 int son[N];
 16 int A[N], B[N], C[N];
 17 
 18 inline void Init()
 19 {
 20     memset(head, -1, sizeof head);
 21     memset(son, 0, sizeof son);
 22     memset(A, 0, sizeof A);
 23     memset(B, 0, sizeof B);
 24     pos = 0; 
 25 }
 26 
 27 inline void addedge(int u, int v) 
 28 {
 29     edge[++pos] = Edge(v, head[u]); head[u] = pos;
 30     edge[++pos] = Edge(u, head[v]); head[v] = pos;
 31 }
 32 
 33 inline void DFS_PRE(int u, int pre)
 34 {
 35     son[u] = 1; int cnt = 0;
 36     for (int it = head[u]; ~it; it = edge[it].nx)
 37     {
 38         int v = edge[it].to; 
 39         if (v == pre) continue;
 40         DFS_PRE(v, u);
 41         cnt += A[v];
 42         son[u] += son[v];    
 43     }
 44     A[u] = max(A[u], cnt);
 45 }
 46 
 47 inline void DFS_CHECK(int u, int pre)
 48 {
 49     int cnt = 1;
 50     for (int it = head[u]; ~it; it = edge[it].nx)
 51     {
 52         int v = edge[it].to;
 53         if (v == pre) continue;
 54         DFS_CHECK(v, u);  
 55         cnt += C[v];
 56     }
 57     C[u] = min(C[u], cnt);
 58 }
 59 
 60 inline bool check(int mid) 
 61 {
 62     for (int i = 1; i <= n; ++i)
 63     {
 64         C[i] = mid - B[i];
 65         if (A[i] > son[i] || B[i] > (n - son[i]) || A[i] > C[i]) return false;
 66     }
 67     //for (int i = 1; i <= n; ++i) printf("%d %d\n", i, C[i]);
 68     DFS_CHECK(1, 1); 
 69     //printf("bug -> %d\n", mid);
 70     //for (int i = 1; i <= n; ++i) printf("%d %d\n", i, C[i]);
 71     for (int i = 1; i <= n; ++i)
 72     {
 73         if (A[i] > C[i]) return false; 
 74     }
 75     return C[1] >= mid;
 76 }
 77 
 78 inline void Run()
 79 {
 80     int t; scanf("%d", &t);
 81     while (t--)
 82     {
 83         scanf("%d", &n); Init();
 84         for (int i = 1, u, v; i < n; ++i)
 85         {
 86             scanf("%d%d", &u, &v);
 87             addedge(u, v);
 88         }
 89         int tot, u, v;
 90         scanf("%d", &tot); 
 91         while (tot--)
 92         {
 93             scanf("%d%d", &u, &v);
 94             A[u] = max(A[u], v);
 95         }
 96         scanf("%d", &tot);
 97         while (tot--) 
 98         {
 99             scanf("%d%d", &u, &v);
100             B[u] = max(B[u], v); 
101         }
102         DFS_PRE(1, 1);
103         int l = 0, r = n, ans = -1;
104         while (r - l >= 0)
105         {
106             int mid = (l + r) >> 1; 
107             if (check(mid))
108             {
109                 ans = mid;
110                 r = mid - 1;
111             }
112             else
113                 l = mid + 1;
114         }
115         printf("%d\n", ans);
116     }
117 }
118 
119 int main()
120 {
121     #ifdef LOCAL
122         freopen("Test.in", "r", stdin);
123     #endif
124 
125     Run();
126     
127     return 0;
128 }
View Code

 

 
M - Geometry Problem
题意:给出n个点,求一个圆心以及半径,使得有一半以上的点在这个圆上
思路:随机选三个点,构成外接圆 判断一下 是不是 n <= 4 的时候 特判
 
 
  1 #include <bits/stdc++.h>
  2 using namespace std; 
  3 
  4 const double eps = 1e-3;
  5 
  6 inline int sgn(double x)
  7 {
  8     if (fabs(x) < eps) return 0;
  9     if (x < 0) return -1;
 10     return 1;
 11 }
 12 
 13 struct Point
 14 {
 15     double x, y;
 16     inline Point() {}
 17     inline Point(double x, double y) : x(x), y(y) {}
 18     inline void scan() { scanf("%lf%lf", &x, &y); }
 19     inline Point operator + (const Point &b) const { return Point(x + b.x, y + b.y); }
 20     inline Point operator - (const Point &b) const { return Point(x - b.x, y - b.y); }
 21     inline Point operator / (const double &k) const { return Point(x / k, y / k); }
 22     inline Point operator * (const double &k) const { return Point(x * k, y * k); }
 23     inline double operator ^ (const Point &b) const { return x * b.y - y * b.x; }
 24     inline double operator * (const Point &b) const { return x * b.x + y * b.y; }
 25     inline double distance(Point b) { return hypot(x - b.x, y - b.y); }
 26     inline Point rotleft() { return Point(-y, x); }
 27 };
 28 
 29 struct Line
 30 {
 31     Point s, e;
 32     inline Line() {}
 33     inline Line(Point s, Point e) : s(s), e(e) {}
 34     inline Point crosspoint(Line v)
 35     {
 36         double a1 = (v.e - v.s) ^ (s - v.s);
 37         double a2 = (v.e - v.s) ^ (e - v.s);
 38         return Point((s.x * a2 - e.x * a1) / (a2 - a1), (s.y * a2 - e.y * a1) / (a2 - a1));
 39     }
 40     inline int relation(Point p)
 41     {
 42         int c = sgn((p - s) ^ (e - s));
 43         if (c < 0) return 1;
 44         if (c > 0) return 2;
 45         return 3;
 46     }
 47 };
 48 
 49 struct Circle
 50 {
 51     Point p;
 52     double r;
 53     inline Circle() {}
 54     inline Circle(Point p, double r) : p(p), r(r) {}
 55     inline Circle(Point a, Point b, Point c)
 56     {
 57         Line u = Line((a + b) / 2, ((a + b) / 2) + ((b - a).rotleft()));
 58         Line v = Line((b + c) / 2, ((b + c) / 2) + ((c - b).rotleft()));
 59         p = u.crosspoint(v);
 60         r = p.distance(a);
 61     }
 62 };
 63 
 64 int t, n;
 65 vector <Point> v;
 66 
 67 inline void Run()
 68 {
 69     scanf("%d", &t);
 70     while (t--)
 71     {
 72         scanf("%d", &n);
 73         double x, y; v.clear();
 74         for (int i = 1; i <= n; ++i)
 75         {
 76             scanf("%lf%lf", &x, &y);
 77             v.emplace_back(x, y);
 78         }
 79         if (n == 1)
 80         {
 81             printf("%.6f %.6f 0\n", v[0].x, v[0].y); 
 82             continue;
 83         }
 84         else if (n <= 4)
 85         {
 86             Point ans = Point((v[0].x + v[1].x) / 2, (v[0].y + v[1].y) / 2);
 87             double dis = ans.distance(v[0]);
 88             printf("%.6f %.6f %.6f\n", ans.x, ans.y, dis); 
 89             continue;
 90         }
 91         else
 92         {
 93             Circle cir;
 94             while (true)
 95             {
 96                 random_shuffle(v.begin(), v.end());  
 97                 //if (Line(v[0], v[1]).relation(v[2]) == 3) continue; 
 98                 cir = Circle(v[0], v[1], v[2]); 
 99                 int cnt = 3;
100                 for (int i = 3, len = v.size(); i < len; ++i)
101                     if (fabs(cir.p.distance(v[i]) - cir.r) < eps) ++cnt; 
102                 if (cnt >= ((n + 1) >> 1))
103                     break;
104             }
105             printf("%.6f %.6f %.6f\n", cir.p.x, cir.p.y, cir.r);
106         }
107     }
108 }
109 
110 int main()
111 {
112     #ifdef LOCAL
113         freopen("Test.in", "r", stdin);
114     #endif
115 
116     Run();
117     
118     return 0;
119 }
View Code

 

posted @ 2018-08-23 17:08  Dup4  阅读(407)  评论(0编辑  收藏  举报