poj 2549 折半枚举+二分

三重循环肯定TLE,所以采用“折半枚举”的方法+二分查找来提高速度,不同的是需要保存两个下标用来判定是否有重复元素。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdio>
 5 using namespace std;
 6
 7 const int N = 1000;
 8 int a[N];
 9 int n, cnt;
10
11 struct Node
12 {
13     int ai, aj, v;
14     bool operator < ( const Node & o ) const
15     {
16         return v < o.v;
17     }
18 } node[N * N];
19
20 void solve()
21 {
22     for ( int i = n - 1; i > 0; i-- )
23     {
24         for ( int j = i - 1; j >= 0; j-- )
25         {
26             Node tmp;
27             tmp.v = a[i] - a[j];
28             int pos = lower_bound( node, node + cnt, tmp ) - node;
29             while ( node[pos].v == tmp.v )
30             {
31                 if ( node[pos].ai != a[i] && node[pos].ai != a[j]
32                   && node[pos].aj != a[i] && node[pos].aj != a[j] )
33                 {
34                     printf("%d\n", a[i]);
35                     return ;
36                 }
37                 pos++;
38             }
39         }
40     }
41     printf("no solution\n");
42 }
43
44 int main ()
45 {
46     while ( scanf("%d", &n) != EOF )
47     {
48         if ( n == 0 ) break;
49         cnt = 0;
50         for ( int i = 0; i < n; i++ )
51         {
52             scanf("%d", a + i);
53             for ( int j = i - 1; j >= 0; j-- )
54             {
55                 node[cnt].ai = a[i];
56                 node[cnt].aj = a[j];
57                 node[cnt].v = a[i] + a[j];
58                 cnt++;
59             }
60         }
61         sort( node, node + cnt );
62         node[cnt].v = 999999999;
63         sort( a, a + n );
64         solve();
65     }
66     return 0;
67 }
时间: 2024-08-12 15:16:54

poj 2549 折半枚举+二分的相关文章

CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。

1514: Packs Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 61  Solved: 4[Submit][Status][Web Board] Description Give you n packs, each of it has a value v and a weight w. Now you should find some packs, and the total of these value is max, total of

Eqs 折半枚举+二分查找 大水题

Eqs 题目抽象:a1x13+ a2x23+ a3x33+ a4x43+ a5x53=0 (*),给出a1,a2,a3,a4,a5.    ai属于[-50,50]. 求有多少序列   x1,x2,x3,x4,x5 ,xi属于 [-50,50]-{0}. 思路:折半枚举+二分查找 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #inclu

poj 3977 Subset 枚举+二分

首先分成一半2^17和2^18,并且把其中一半变成相反数,然后枚举一半二分查找另一半,在找到的位置前后也找找. 这里用到了二级排序,有很多细节要处理,不多说了. 巨坑的一个地方就是,不能用系统的abs,要自己手写,简直坑死.. #include<cstdio> #include<algorithm> #include<iostream> #include<map> using namespace std; typedef long long ll; stru

POJ 3977Subset(枚举+二分)

Subset Time Limit: 30000MS   Memory Limit: 65536K Total Submissions: 1562   Accepted: 261 Description Given a list of N integers with absolute values no larger than 1015, find a non empty subset of these numbers which minimizes the absolute value of

POJ 2785 折半枚举

#include <cstdio> #include <iostream> #include <algorithm> #define LL long long using namespace std; int a[4][4005]; int b[2][4005*4005]; int main(){ int n; while(cin >> n){ for(int i = 0;i < n;i++){ for(int j = 0;j < 4;j++){

Subset---poj3977(折半枚举+二分查找)

题目链接:http://poj.org/problem?id=3977 给你n个数,找到一个子集,使得这个子集的和的绝对值是最小的,如果有多种情况,输出子集个数最少的: n<=35,|a[i]|<=10e15 子集个数共有2^n个,所以不能全部枚举,但是可以分为两部分枚举: 枚举一半的所有情况,然后后一半二分即可: #include<iostream> #include<algorithm> #include<string.h> #include<st

poj3977(折半枚举+二分查找)

题目链接:https://vjudge.net/problem/POJ-3977 题意:给一个大小<=35的集合,找一个非空子集合,使得子集合元素和的绝对值最小,如果有多个这样的集合,找元素个数最少的. 思路:显然,可以用折半搜索,分别枚举一半,最大是2的18次方,复杂度能够满足.因为集合非空,枚举时考虑只在前一半选和只在后一半选的情况.对于前一半后一半都选的情况,把前一半的结果存下来,排序,枚举后一半的时候在前一半里二分查找最合适的即可. 思路不难,实现有很多细节,最开始用dfs写得一直wa,

poj 2785 4 Values whose Sum is 0 折半枚举

题目链接:http://poj.org/problem?id=2785 枚举的一般思路就是先把所有的状态枚举出来 最后一次性判断该状态合法不合法 而折半枚举的思想是 先枚举一半的状态 把他们的状态存起来 排序 然后再枚举剩下一般 用目标反推前一半的期望状态 接下来在前一半的结果数组中查找是否有相应结果 之所以能优化是因为结果数组有序 就可以用二分搜索 复杂度从O(n^2 * n^2) 降到 O(n^2 * log(n^2))即(O(n^2 * log n)) 二分搜索的一个技巧 在有序数组中用二

Codeforces 912 E.Prime Gift (折半枚举、二分)

题目链接:Prime Gift 题意: 给出了n(1<=n<=16)个互不相同的质数pi(2<=pi<=100),现在要求第k大个约数全在所给质数集的数.(保证这个数不超过1e18) 题解: 如果暴力dfs的话肯定超时间,其实给的n数据范围最大是16是一个很奇妙的数(一般折半枚举基本上是这样的数据范围@.@-).所以想到折半枚举,把所有的质数分成两份求出每份中所有小于1e18的满足条件的数.然后二分答案,写cheak函数时遍历第一个集合,对第二个集合二分(折半枚举基本上这个套路).