问题 C: 神使
题目描述
在一个神秘的王国里,有一位伟大的勇者正在寻找他的最佳战斗伙伴。王国里有n个勇士,每个勇士的战斗力值记为ai。勇者决定通过一场淘汰赛来选择最终的战斗伙伴,比赛规则如下:
竞技场将进行n-1轮投票淘汰,每轮淘汰一个勇士。
在每一轮中,第i个勇士会将自己的一票投给与自己战斗力值差距最大的勇士,即找到j,使得|ai-aj|最大。此轮得票最多的勇士将被淘汰。
如果有多个勇士得票相同,战斗力值较大的勇士优先被淘汰。
如果第i个勇士在本轮中有多个差距相同的候选目标,他会优先投票给战斗力值较大的勇士。
勇者想知道,在所有轮次结束后,剩下的勇士是谁。
保证所有勇士战力值不同
输入
第一行包含一个整数n,表示有n个勇士。
第二行包含n个整数,第i个整数ai表示第i个勇士的战斗力值。
输出
输出一行一个整数,表示最终剩下的勇士的编号。
样例输入
5
2 3 6 1 10
样例输出
4
提示
对于30%的数据,满足 n≤20,0≤ai≤1000
对于50%的数据,满足n≤5000,0≤ai≤10^5
对于100%的数据,满足n≤10,-109≤ai≤109
分析
从直观上我们应该选择数据稀疏的一边的边界淘汰掉,怎么刻画数据的稀疏呢?我们可以想到,边界之间的值一个界点,分界点左边离右边边界远,全投给右边,左边类似,那么怎么精确刻画呢?对于v[0]
和v[n-1]
,如果<=(v[0]+v[n-1])/2
的数据数量更多,那么右边界值应该淘汰,如果两边一样多,也舍弃右边界值,反之,淘汰左边界值,那么只要重复到只有最后一个值就可以了,那么可以使用双指针,使用upper_bound()
求区间大于中间值的索引,然后算两边的数量。
我的错误:1)搞错lower_bound()
的功能,是求大于等于的值 2)求数量上搞错计算的边界
代码
#include <bits/stdc++.h>
#include <iostream>
#define de(x) cout << #x << " = " << (x) << endl;
#define de2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
#define de3(x,y,z) cout << #x << " = " << (x) << " " << #y << " = " << (y )<< " " << #z << " = " << (z) << endl;
#define f(i,a,b) for(int i = a;i < b;++i)
#define fd(i,a,b) for(int i = a;i >= b;--i)
#define fro for
#define mem(a) memset(a,0,sizeof(a))typedef long long ll;
typedef unsigned long long ull;
using namespace std;
//
// string l_plus(string a, string b)
// {
// vector<int> n(10000,0);
// vector<int> m(10000,0);
// vector<int> sum(10000,0);
//
// int la = a.size();
// int lb = b.size();
//
// for(int i = la - 1;i >= 0;--i)
// {
// n[la-i-1] = a[i] - '0';
// //de(i);
// }
// for(int i = lb - 1;i >= 0;--i)
// {
// m[lb-i-1] = b[i] - '0';
// //de(i);
// }
//
// //add
// ll add = 0;
// int len = max(la, lb);
// for(int i = 0;i < len;++i)
// {
// sum[i] = n[i] + m[i] + add;
// add = sum[i]/10;
// sum[i] %= 10;
// //cout << sum[i] << " ";
//
// }
// if(add!= 0)
// {
// sum[len] = add;
// len++;
// //de(len);
// }
//
// string res = "";
// for(int i = len -1;i >= 0;--i)
// {
// char ch = sum[i] + '0';
// res += ch;
// //de(ch);
// }
// //cout << res;
//
// return res;
// }// string L_Subtraction(string s1,string s2)
// {
// bool neg = false;
// int len1 = s1.size(),len2 = s2.size();
// if(len1 < len2 || s1 < s2)//符号判定
// {
// neg = true;
// swap(s1,s2);
// swap(len1,len2);
// }
// vector<int> a1(len1,0),a2(len1,0),ans(len1,0);//特别注意,算减法的时候会访问到len1的长度,小心a2越界!!!
// for(int i = 0;i < len1;++i)
// {
// a1[i] = s1[len1 - 1 - i] - '0';
// }
//
// for(int i = 0;i < len2;++i)
// {
// a2[i] = s2[len2 - 1 - i] - '0';
// }
//
// for(int i = 0;i < len1;++i)
// {
// int temp = a1[i] - a2[i];
// if(temp< 0)
// {
// temp += 10;
// a1[i+1]--;
// }
// ans[i] = temp;//别忘了
// }
//
// string anss = "";
// if(neg)
// anss = "-" + anss;
// int i = len1-1;//len1-1是最末尾,小心越界
// for(;i > 0 && ans[i]==0;++i);
//
// for(;i >= 0;--i)
// {
// anss += ans[i] + '0';
// }
// return anss;
// }//
// string h_mult_l(string s1,string s2)
// {
// int len = s1.size();
// long long a = stoi(s2);
// vector<long long> ans(len + s2.size(),0);
// for(int i = 0;i < len ;++i)
// {
// long long temp = 1LL * (s1[len - 1 - i] - '0') * a;
// ans[i] += temp;//注意处理顺序
// ans[i+1] += ans[i]/10;//当前位一共的进位
// ans[i] %= 10;//最后处理当前位
// }
// if(ans[len] >= 10)//注意多余进位
// {
// int le = len;
// long long t = ans[len];
// while (t)
// {
// ans[le++] = t%10;
// t/= 10;
// }
// }
// string res = "";
// int i = len + s2.size() - 1;
// for(;i > 0 && ans[i] == 0;--i);
// for(;i >= 0;--i)
// {
// res += ans[i] + '0';
// }
// return res;
// }//
// string h_mult_h(string s1,string s2)
// {
// int len1 = s1.size(),len2 = s2.size();
// vector<int> a1(len1,0),a2(len2,0),ans(len1+len2+1,0);
// for(int i = 0;i < len1;++i)
// {
// a1[i] = s1[len1 - 1 - i] - '0';
// }
// for(int i = 0;i < len2;++i)
// {
// a2[i] = s2[len2 - 1 - i] - '0';
// }
// for(int i = 0;i < len1;++i)
// {
// for(int j = 0;j < len2;++j)
// {
// ans[i+j] += a1[i] * a2[j];
// ans[i+j+1] += ans[i+j]/10;
// ans[i+j] %= 10;
// }
// }
// if(ans[len1 + len2 - 1] > 10)
// {
// ans[len1 + len2] = ans[len1 + len2 -1]/10;
// ans[len1 + len2 - 1] %= 10;
// }
// string res = "";
// int i = len1 + len2;
// for(;i > 0 && ans[i] == 0;--i);
// for(;i >= 0;--i)
// {
// res += ans[i] + '0';
// }
// return res;
//
//
// }// int n,m,e;
// vector<vector<int>> g; // 邻接矩阵
// vector<bool> vis; // 标记当前遍历中是否访问过
// vector<int> linked; // 每个右侧点匹配的左侧点
// bool dfs(int x)
// {
// for(int i = 1;i <= m;++i)
// {
// if(g[x][i] && !vis[i])
// {
// vis[i] = true;// 标记为已访问
// if(linked[i] == -1 || dfs(linked[i]))// 匹配点为空或递归找到增广路
// {
// linked[i] = x;// 更新匹配关系
// return true;
// }
// }
//
// }
//
// return false;
// }//链式向前星
//
// int n,m,s;
// const int N = 1000100;
// int dis[N];
// struct eage
// {
// int to, dis, next;
// };
// int cnt = 0;
// int head[N];
// eage e[N];
// bool vis[N];
//
// void add_edge(int from,int tod, int w)
// {
// cnt++;
// e[cnt].to = tod;
// e[cnt].dis = w;
// e[cnt].next = head[from];
// head[from] = cnt;
// }// int fa[30005];
// void init()
// {
// for(int i = 1;i <= 30000;++i) fa[i] = i;
// }
// int finds(int x)
// {
// if(fa[x] == x) return x;
// else return finds(fa[x]);
// }
// void <bvtag class="memorize_new_word bv_icpc_upc_edu_cn bv_browserName_google_chrome burning_vocabulary _id_1737264440897">merge</bvtag>(int x,int y)
// {
// fa[finds(x)] = finds(y);
// }#define int long long
struct cow {int id,val;bool operator < (const cow a) const {return val < a.val;}bool operator > (const cow a) const {return val > a.val;}
};
signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);//// freopen("E:/Code/C++/untitled1/input.txt","r",stdin);// freopen("output.txt","w",stdout);int n;cin >> n;vector<cow> v(n);for (int i = 0;i < n;++i) cin >> v[i].val,v[i].id= i+1;sort(v.begin(),v.end());int l = 0,r = n-1;while (l < r) {cow mid;mid.val = v[l].val+v[r].val>>1; int nub = upper_bound(v.begin()+l,v.begin()+r,mid) - (v.begin()); //算真正的索引,不是相对的if ((nub-l)>=r-nub+1) r--; //使用实例测试一下怎么算的else l++;}cout << v[r].id;}