POJ 2-SAT 六题
POJ 3207 - Ikki's Story IV - Panda's Trick
http://acm.pku.edu.cn/JudgeOnline/problem?id=3207
POJ 3678 - Katu Puzzle
http://acm.pku.edu.cn/JudgeOnline/problem?id=3678
POJ 2723 - Get Luffy Out
http://acm.pku.edu.cn/JudgeOnline/problem?id=2723
POJ 3683 - Priest John's Busiest Day
http://acm.pku.edu.cn/JudgeOnline/problem?id=3683
POJ 2749 - Building roads
http://acm.pku.edu.cn/JudgeOnline/problem?id=2749
POJ 3648- Wedding
http://acm.pku.edu.cn/JudgeOnline/problem?id=3648
POJ 3207 Ikki's Story IV - Panda's Trick
题意:一个圆的边上有n个编号连续的点,要用m条线把这些点连起来,并且线不可以相交。(这些线可以从圆内连也可以从圆外绕过去),问是否有符合条件的m条边。
思路:把一条边看成一个点,如果 i 线和 j 线相交则表示i j 冲突则连接 i -> ~j, j -> ~i。因为这里i j都是必然出现的,所以要连成无向图。
渣代码:
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <vector>
5
6 using namespace std;
7
8 const int N = 1010;
9 const int M = 5000005;
10
11 struct node {
12 int to;
13 int next;
14 } g[M];
15
16 int head[N], scc[N];
17 int dfn[N], low[N];
18 int a[2][N], s[N];
19 int t, ind, cnt, top;
20 bool vis[N];
21
22 void swap(int *a, int *b) {
23 int *t;
24 t = a; a = b; b = t;
25 }
26
27 void init() {
28 for(int i = 0; i < N; i++) {
29 head[i] = scc[i] = dfn[i] = low[i] = vis[i] = 0;
30 }
31 t = 1; ind = cnt = top = 0;
32 }
33
34 void add(int u, int v) {
35 g[t].to = v; g[t].next = head[u]; head[u] = t++;
36 }
37
38 void dfs(int u) {
39 int v, i;
40 dfn[u] = low[u] = ++ind;
41 s[++top] = u; vis[u] = true;
42 for(i = head[u]; i; i = g[i].next) {
43 v = g[i].to;
44 if(!dfn[v]) {
45 dfs(v);
46 low[u] = min(low[u], low[v]);
47 } else if(vis[v]) {
48 low[u] = min(low[u], dfn[v]);
49 }
50 }
51 if(dfn[u] == low[u]) {
52 cnt++;
53 do {
54 v = s[top--];
55 //printf("%d %d\n", v, cnt);
56 scc[v] = cnt;
57 vis[v] = false;
58 } while(v != u);
59 }
60 }
61
62 void tarjan(int n) {
63 for(int i = 0; i < n; i++) {
64 if(!dfn[i]) dfs(i);
65 }
66 }
67
68 bool solve(int n) {
69 tarjan(n);
70 for(int i = 0; i < n; i += 2) {
71 if(scc[i] == scc[i+1]) return false;
72 }
73 return true;
74 }
75
76 int main() {
77 //freopen("data.in", "r", stdin);
78
79 int n, m;
80 int i, j;
81 while(~scanf("%d%d", &n, &m)) {
82 init();
83 for(i = 0; i < m; i++) {
84 scanf("%d%d", &a[0][i], &a[1][i]);
85 if(a[0][i] > a[1][i]) swap(a[0][i], a[1][i]);
86 //printf("%d %d\n", a[0][i], a[1][i]);
87 for(j = 0; j < i; j++) {
88 if((a[0][j] < a[0][i] && a[1][j] > a[0][i] && a[1][j] < a[1][i])
89 || (a[0][j] > a[0][i] && a[0][j] < a[1][i] && a[1][j] > a[1][i])) {
90 add((i<<1), (j<<1) + 1); add((j<<1) + 1, (i<<1));
91 //printf("%d %d %d %d\n", (i<<1), (j<<1) + 1, (j<<1) + 1, (i<<1));
92 add((j<<1), (i<<1) + 1); add((i<<1) + 1, (j<<1));
93 //printf("%d %d %d %d\n", (j<<1), (i<<1) + 1, (i<<1) + 1, (j<<1));
94 }
95 }
96 }
97 if(solve(m<<1)) cout << "panda is telling the truth..." << endl;
98 else cout << "the evil panda is lying again" << endl;
99 }
100 return 0;
101 }
POJ 3678 解题报告:http://www.cnblogs.com/vongang/archive/2012/02/15/2352246.html
POJ 2723 Get Luffy Out
题意:给m个门,每个门上有两把锁(总共2N种锁),打开其中一把就可以把们打开。现在有2N把钥匙,组成N个钥匙对,问最多能开几扇门(开完1号才能开2号,依次类推)
思路:设x, y组成的钥匙对,可知 x XOR y = 1;所以 x -> ~y, y -> ~x;
每扇门上的锁x, y,可知x | y = 1; 所以~x, 和~y矛盾,所以 ~x -> y, ~y -> x;
然后二分建图,求出能开的门数。
ps:g++能过,c++ wa, 纠结。
渣代码:
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4
5 using namespace std;
6
7 const int N = 5000;
8 const int M = 60000;
9
10 struct node {
11 int to;
12 int next;
13 } g[M];
14
15 int head[N], scc[N];
16 int dfn[N], low[N], s[M];
17 int a[2][N], b[2][N];
18 int t, top, n, ind, cnt;
19
20 bool vis[N];
21
22 void init() {
23 for(int i = 0; i <= N; i++) {
24 head[i] = low[i] = dfn[i] = vis[i] = 0;
25 }
26 t = 1; ind = top = cnt = 0;
27 }
28
29 void add(int u, int v) {
30 g[t].to = v; g[t].next = head[u]; head[u] = t++;
31 }
32
33 void dfs(int u) {
34 int v, i;
35 dfn[u] = low[u] = ++ind;
36 s[top++] = u; vis[u] = true;
37 for(i = head[u]; i; i = g[i].next) {
38 v = g[i].to;
39 if(!dfn[v]) {
40 dfs(v);
41 low[u] = min(low[u], low[v]);
42 } else if(vis[v]) {
43 low[u] = min(low[u], dfn[v]);
44 }
45 }
46 if(low[u] == dfn[u]) {
47 cnt++;
48 do {
49 v = s[--top];
50 scc[v] = cnt;
51 vis[v] = false;
52 } while(u != v);
53 }
54 }
55
56 void tarjan() {
57 for(int i = 0; i < n<<2; i++) {
58 if(!dfn[i]) dfs(i);
59 }
60 }
61
62 void creat_g(int m) {
63 int i;
64 for(i = 0; i < n; i++) {
65 add((a[0][i]<<1), (a[1][i]<<1) + 1);
66 add((a[1][i]<<1), (a[0][i]<<1) + 1);
67 }
68 for(i = 0; i < m; i++) {
69 add((b[0][i]<<1) + 1, (b[1][i]<<1));
70 add((b[1][i]<<1) + 1, (b[0][i]<<1));
71 }
72 }
73
74 bool solve() {
75 tarjan();
76 for(int i = 0; i < n<<2; i += 2) {
77 if(scc[i] == scc[i+1]) return false;
78 }
79 return true;
80 }
81
82 int main() {
83 //freopen("data.in", "r", stdin);
84
85 int m, i;
86 while(~scanf("%d%d", &n, &m)) {
87 if(!n && !m) break;
88 memset(a, 0, sizeof(a));
89 memset(b, 0, sizeof(b));
90
91 for(i = 0; i < n; i++) {
92 scanf("%d%d", &a[0][i], &a[1][i]);
93 }
94 for(i = 0; i < m; i++) {
95 scanf("%d%d", &b[0][i], &b[1][i]);
96 }
97
98 int l = 0, r = m, mid;
99 while(l <= r) {
100 mid = (l + r) >> 1;
101 init();
102 creat_g(mid);
103 if(solve()) l = mid + 1;
104 else r = mid - 1;
105 //printf("%d %d %d\n", l, r, mid);
106 }
107 printf("%d\n", r);
108 }
109 return 0;
110 }
POJ 3683 - Priest John's Busiest Day
题意很清楚。关键是输出一组可行解。
思路:把开始时间短,结束时间段看成两个对立的点,建图方法同POJ 3207。输出时根据赵爽的论文 + 网上的输出可行解模板。。。终于A了。
输出可行解部分的思路:
按缩点以后的有向无环图的边反向建图G。以G上所有入度为0的点为始点,将其染成红色,和这些点对立的点染成绿色,然后按图进行拓扑排序。知道所有的点都染色。
关键部分代码:
1 for(i = 0; i < t; i++) {
2 if(scc[g[i].to] != scc[g[i].from]) { //反向建图
3 addG(scc[g[i].to], scc[g[i].from]);
4 //printf("%d %d %d %d\n", g[i].to, g[i].from, scc[g[i].to], scc[g[i].from]);
5 indeg[scc[g[i].from]]++;
6 }
7 }
8 for(i = 1; i <= cnt; i++) {
9 if(indeg[i] == 0) q.push(i); //入度为0的点入队列
10 }
11
12 while(!q.empty()) { //进行拓扑排序
13 u = q.front();
14 if(col[u] == 0) { //未染色的入度为0的点染成红色,其对立点染成绿色
15 col[u] = 1;
16 col[opp[u]] = -1;
17 }
18 q.pop();
19 for(i = head[u]; i; i = G[i].next) {
20 v = G[i].to;
21 indeg[v]--;
22 if(indeg[v] == 0) {
23 q.push(v);
24 }
25 }
26 }
完整版:
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <queue>
5
6 using namespace std;
7
8 const int N = 2012;
9 const int M = 2000000;
10
11 struct node {
12 int from;
13 int to;
14 int next;
15 } g[M], G[M];
16
17 struct timm {
18 int l;
19 int r;
20 } tim[N];
21
22 int head[N], scc[N];
23 int dfn[N], low[N];
24 int s[N], col[N];
25 int indeg[N], opp[N];
26 bool vis[N], ans[N];
27
28 int t, tg, ind, cnt, top;
29
30 void init() {
31 for(int i = 0; i < N; i++) {
32 col[i] = indeg[i] = ans[i] = 0;
33 head[i] = scc[i] = dfn[i] = low[i] = vis[i] = 0;
34 }
35 memset(tim, 0, sizeof(tim));
36 tg = t = 1; ind = cnt = top = 0;
37 }
38
39 void add(int u, int v) {
40 g[t].from = u; g[t].to = v; g[t].next = head[u]; head[u] = t++;
41 }
42
43 void addG(int u, int v) {
44 G[tg].from = u; G[tg].to = v; G[tg].next = head[u]; head[u] = tg++;
45 }
46
47 void dfs(int u) {
48 int v, i;
49 dfn[u] = low[u] = ++ind;
50 s[top++] = u; vis[u] = true;
51 for(i = head[u]; i; i = g[i].next) {
52 v = g[i].to;
53 if(!dfn[v]) {
54 dfs(v);
55 low[u] = min(low[u], low[v]);
56 } else if(vis[v]) {
57 low[u] = min(low[u], dfn[v]);
58 }
59 }
60 if(dfn[u] == low[u]) {
61 cnt++;
62 do {
63 v = s[--top];
64 scc[v] = cnt;
65 vis[v] = false;
66 } while(u != v);
67 }
68 }
69
70 void tarjan(int n) {
71 for(int i = 0; i < n; i++) {
72 if(!dfn[i]) dfs(i);
73 }
74 }
75
76 bool sat(int n) {
77 tarjan(n);
78 for(int i = 0; i < n; i += 2) {
79 if(scc[i] == scc[i+1]) return false;
80 opp[scc[i]] = scc[i+1];
81 opp[scc[i+1]] = scc[i];
82 }
83 return true;
84 }
85
86 void topo(int n) {
87 queue<int> q;
88 memset(col, 0, sizeof(col));
89 memset(head, 0, sizeof(head));
90 int i, u, v;
91 for(i = 0; i < t; i++) {
92 if(scc[g[i].to] != scc[g[i].from]) {
93 addG(scc[g[i].to], scc[g[i].from]);
94 //printf("%d %d %d %d\n", g[i].to, g[i].from, scc[g[i].to], scc[g[i].from]);
95 indeg[scc[g[i].from]]++;
96 }
97 }
98 for(i = 1; i <= cnt; i++) {
99 if(indeg[i] == 0) q.push(i);
100 }
101
102 while(!q.empty()) {
103 u = q.front();
104 if(col[u] == 0) {
105 col[u] = 1;
106 col[opp[u]] = -1;
107 }
108 q.pop();
109 for(i = head[u]; i; i = G[i].next) {
110 v = G[i].to;
111 indeg[v]--;
112 if(indeg[v] == 0) {
113 q.push(v);
114 }
115 }
116 }
117 for(i = 0; i < n<<1; i += 2) {
118 if(col[scc[i]] == 1) {
119 //printf("%d\n", i);
120 printf("%02d:%02d %02d:%02d\n", tim[i].l/60, tim[i].l%60, tim[i].r/60, tim[i].r%60);
121 } else {
122 //printf("%d\n", i+1);
123 printf("%02d:%02d %02d:%02d\n", tim[i + 1].l/60, tim[i + 1].l%60, tim[i + 1].r/60, tim[i + 1].r%60);
124 }
125 }
126 }
127
128 int main() {
129 //freopen("data.in", "r", stdin);
130
131 int n, i, j;
132 int x, y, a, b, d;
133 while(~scanf("%d", &n)) {
134 init();
135
136 for(i = 0; i < n; i++) {
137 scanf("%d:%d %d:%d %d", &x, &y, &a, &b, &d);
138 x = x*60 + y; a = a*60 + b;
139 tim[i<<1].l = x;
140 tim[i<<1].r = x + d;
141 tim[(i<<1) + 1].l = a - d;
142 tim[(i<<1) + 1].r = a;
143 //printf("%d %d %d %d\n", x, x + d, a - d, a);
144 }
145 for(i = 0; i < 2*n; i++) {
146 for(j = 0; j < 2*n; j++) {
147 if(i == j || (i^1) == j) continue;
148 if(tim[i].l < tim[j].r && tim[j].l < tim[i].r) {
149 //printf("~~%d %d\n", i, j^1);
150 add(i, j^1);
151 }
152 }
153 }
154 if(!sat(n<<1)) {cout << "NO" << endl; continue;}
155 cout << "YES" << endl;
156 topo(n);
157 }
158 return 0;
159 }
POJ 3648- Wedding
题意:一对新人举行婚礼,并邀请很多夫妇参加。其中有一个长桌子,桌子两边可以坐人。新娘因为头发做的太牛叉了,把眼睛都遮住了,所以只能看到桌子对面坐的人,不能看到自己这一面的。同时,新娘如果看到对面做的人里边有夫妇俩会不高兴的。现在知道里边有一些人通奸(也可能是搞基),新娘看到对面的人里边有两个通奸的也会不高兴。现在为了使新娘高兴,请你安排坐次。
思路:奇数表示男士,偶数表示女士。新娘是0号,新郎是1号。连续的两个奇偶数表示夫妇俩。然后按照矛盾关系建图。然后染色求出新郎那一边的就座情况(注意:需要加一条0 -> 1的边。这样如果选到新娘就一定会选到新郎,又因为新郎和新娘不在同一边,所以可以排除掉这种情况)
渣代码:
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <queue>
5
6 using namespace std;
7
8 const int N = 1024;
9 const int M = 100000;
10
11 struct node {
12 int from;
13 int to;
14 int next;
15 } g[M], G[M];
16
17 int head[N], scc[N];
18 int dfn[N], low[N];
19 int col[N], indeg[N];
20 int opp[N], s[N];
21 int t, T, top, cnt, ind;
22 bool vis[N];
23
24 void init() {
25 for(int i = 0; i < N; i++) {
26 opp[i] = head[i] = col[i] = indeg[i] = 0;
27 s[i] = dfn[i] = low[i] = scc[i] = vis[i] = 0;
28 }
29 t = T = 1; ind = cnt = top = 0;
30 }
31
32 void add(int u, int v) {
33 g[t].from = u; g[t].to = v; g[t].next = head[u]; head[u] = t++;
34 }
35
36 void _add(int u, int v) {
37 G[T].from = u; G[T].to = v; G[T].next = head[u]; head[u] = T++;
38 }
39
40 void tarjan(int u) {
41 int v, i;
42 dfn[u] = low[u] = ++ind;
43 vis[u] = true; s[top++] = u;
44 for(i = head[u]; i; i = g[i].next) {
45 v = g[i].to;
46 if(!dfn[v]) {
47 tarjan(v);
48 low[u] = min(low[u], low[v]);
49 } else if(vis[v]) {
50 low[u] = min(low[u], dfn[v]);
51 }
52 }
53 if(dfn[u] == low[u]) {
54 cnt++;
55 do {
56 v = s[--top];
57 //printf("%d %d\n", v, cnt);
58 scc[v] = cnt;
59 vis[v] = false;
60 } while(v != u);
61 }
62 }
63
64 bool solve(int n) {
65 int i;
66 for(i = 0; i < (n<<1); i++) {
67 if(!dfn[i]) tarjan(i);
68 }
69 for(i = 0; i < (n<<1); i += 2) {
70 if(scc[i] == scc[i+1]) return false;
71 opp[scc[i]] = scc[i+1];
72 opp[scc[i+1]] = scc[i];
73 }
74 return true;
75 }
76
77 void topo_sat() {
78 queue<int> q;
79 int i, u, v;
80 memset(head, 0, sizeof(head));
81 for(i = 0; i < t; i++) {
82 if(scc[g[i].to] != scc[g[i].from]) {
83 //printf("%d %d\n", g[i].from, g[i].to);
84 _add(scc[g[i].to], scc[g[i].from]);
85 //printf("%d %d\n", scc[g[i].to], scc[g[i].from]);
86 indeg[scc[g[i].from]] ++;
87 }
88 }
89 for(i = 1; i <= cnt; i++) {
90 if(indeg[i] == 0) q.push(i);
91 }
92 while(!q.empty()) {
93 u = q.front(); q.pop();
94 if(col[u] == 0) {
95 col[u] = 1;
96 col[opp[u]] = -1;
97 }
98 for(i = head[u]; i; i = G[i].next) {
99 v = G[i].to;
100 if(--indeg[v] == 0) q.push(v);
101 }
102 }
103 }
104
105 int main() {
106 //freopen("data.in", "r", stdin);
107
108 int n, m;
109 int x, y, i;
110 char c, d;
111 while(scanf("%d%d", &n, &m), n||m) {
112 init();
113 while(m--) {
114 scanf("%d%c%d%c", &x, &c, &y, &d);
115
116 if(c == 'w') x *= 2;
117 else x = x*2 + 1;
118 if(d == 'w') y *= 2;
119 else y = y*2 + 1;
120 if(x != (y^1)) {
121 add(x, y^1);
122 //printf("%d %d\n", x, y^1);
123 add(y, x^1);
124 //printf("%d %d\n", y, x^1);
125 }
126 }
127 add(0, 1);
128 if(!solve(n)) {cout << "bad luck" << endl; continue;}
129 topo_sat(); x = 0;
130 for(i = 0; i < n<<1; i++) {
131 if(col[scc[i]] == 1 && i != 1) {
132 if(!x) x = 1;
133 else printf(" ");
134 printf("%d", i/2);
135 if(i%2 == 0) putchar('h'); //因为得到的是新郎一边的就坐情况,所以调换一下夫妇的符号就是新娘一边的。
136 else putchar('w');
137 }
138 }
139 cout << endl;
140 }
141 return 0;
142 }
143
144 //ps: 题目要的是一组可行解。有很多种情况
POJ 2749 - Building roads
思路:先按hate关系和friend关系建图,i j为hate关系,则i -> ~j, j -> ~i, ~j -> i, ~i -> j; friend类似。此外,二分时加一个限制然后加边。
设dis1[i]是点i到s1的距离,dis2[i]是点i到s2的距离。i 表示点连s1, ~i表示点连s2.
dis1[i] + dis1[j] > limite i -> ~j, j -> ~i;
dis2[i] + dis2[j] > limite ~i -> j, ~j -> i;
dis1[i] + dis2[j] + D > limite i -> j, ~j -> ~i
dis2[i] + dis1[j] + D > limite ~i - > ~j, j -> i
搞了两天多终于把这六道题搞完了。。。
渣代码:
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <stack>
5
6 using namespace std;
7
8 const int N = 1024;
9 const int M = 500000;
10
11 struct node {
12 int to;
13 int next;
14 } g[M];
15
16 int head[N], scc[N];
17 int low[N], dfn[N];
18 int s[N];
19 bool vis[N];
20
21 int hate[2][N], fri[2][N];
22 int dis1[N], dis2[N];
23
24 int t, top, ind, cnt;
25 int n, a, b, D;
26
27 int ABS(int x) {
28 return x < 0 ? -x : x;
29 }
30
31 void init() {
32 for(int i = 0; i < N; i++) {
33 head[i] = dfn[i] = scc[i] = low[i] = vis[i] = 0;
34 s[i] = 0;
35 }
36 t = 1; top = ind = cnt = 0;
37 }
38
39 void add(int u, int v) {
40 g[t].to = v; g[t].next = head[u]; head[u] = t++;
41 }
42
43 void tarjan(int u) {
44 int v, i;
45 dfn[u] = low[u] = ++ind;
46 s[top++] = u; vis[u] = true;
47
48 for(i = head[u]; i; i = g[i].next) {
49 v = g[i].to;
50 if(!dfn[v]) {
51 tarjan(v);
52 low[u] = min(low[u], low[v]);
53 } else if(vis[v]) {
54 low[u] = min(low[u], dfn[v]);
55 }
56 }
57 if(dfn[u] == low[u]) {
58 cnt++;
59 do {
60 v = s[--top];
61 //printf("**%d %d\n", v, cnt);
62 scc[v] = cnt;
63 vis[v] = false;
64 } while(v != u);
65 }
66 }
67
68 void rebuild(int lim) {
69 int i, j, x, y;
70 for(i = 0; i < a; i++) {
71 x = hate[0][i]*2; y = hate[1][i]*2;
72 add(x, y + 1); add(y, x + 1);
73 add(y + 1, x); add(x + 1, y);
74 //printf("%d %d\n", x, y);
75 }
76 for(i = 0; i < b; i++) {
77 x = fri[0][i]*2; y = fri[1][i]*2;
78 add(x, y); add(x + 1, y + 1);
79 add(y, x); add(y + 1, x + 1);
80 //printf("%d -> %d\n", x, y);
81 }
82 for(i = 0; i < n; i++) {
83 for(j = i + 1; j < n; j++) {
84 x = i<<1, y = j << 1;
85 if(dis1[i] + dis1[j] > lim) {add(x, y + 1); add(y, x + 1);}
86 if(dis2[i] + dis2[j] > lim) {add(x + 1, y); add(y + 1, x);}
87 if(dis1[i] + dis2[j] + D > lim) {add(x, y); add(y + 1, x + 1);}
88 if(dis2[i] + dis1[j] + D > lim) {add(x + 1, y + 1); add(y, x);}
89 }
90 }
91 }
92
93 bool solve(int lim) {
94 init();
95 rebuild(lim);
96 for(int i = 0; i < n<<1; i++) {
97 if(!dfn[i]) tarjan(i);
98 }
99 for(int i = 0; i < n; i ++) {
100 if(scc[i<<1] == scc[i<<1|1]) return false;
101 }
102 return true;
103 }
104
105 int main() {
106 //freopen("data.in", "r", stdin);
107
108 int i, m, x, y;
109 int sx1, sx2, sy1, sy2;
110 while(~scanf("%d%d%d", &n, &a, &b)) {
111 scanf("%d%d%d%d", &sx1, &sy1, &sx2, &sy2);
112 D = ABS(sx1 - sx2) + ABS(sy1 - sy2);
113 m = -1;
114 for(i = 0; i < n; i++) {
115 scanf("%d%d", &x, &y);
116 dis1[i] = ABS(x - sx1) + ABS(y - sy1);
117 dis2[i] = ABS(x - sx2) + ABS(y - sy2);
118 m = max(m, max(dis1[i], dis2[i]));
119 }
120 for(i = 0; i < a; i++) {
121 scanf("%d%d", &hate[0][i], &hate[1][i]);
122 hate[0][i] --; hate[1][i]--;
123 }
124 for(i = 0; i < b; i++) {
125 scanf("%d%d", &fri[0][i], &fri[1][i]);
126 fri[0][i]--; fri[1][i]--;
127 }
128 int l = 0, r = m*3, mid, ans = -1;
129 while(l <= r) {
130 mid = (l + r) >> 1;
131 if(solve(mid)) {
132 ans = mid;
133 r = mid - 1;
134 }
135 else l = mid + 1;
136 //printf("%d %d %d\n", l, r, mid);
137 }
138 printf("%d\n", ans);
139 }
140 return 0;
141 }