A题比较简单就不说了。
B题也比较简单,md,但是写法有问题。
- struct排序函数
bool cmp(node a,node b)
{
return a.t<b.t;//点前不同,点后同。
}
- 而是要理清题意,我就排序关键字错了。
C题
- 题目链接
- 题意
给你n个全排列;你每次问一个位置的数字,然后会返回一个 a i a_{i} ai ;要求你在100次内找到 k k k 使得 a k < m i n ( a k + 1 , a k − 1 ) a_{k}<min(a_{k+1},a_{k-1}) ak<min(ak+1,ak−1) 。 - 思路
首先判断 a [ 1 ] a[1] a[1] 和 a [ n ] a[n] a[n] 是不是局部最小值,假如是则输出。
否则: a [ 1 ] a[1] a[1] 到 a [ 2 ] a[2] a[2] 呈下降趋势, a [ n ] a[n] a[n] 到 a [ n − 1 ] a[n - 1] a[n−1] 呈下降趋势,则 2 2 2 ~ n − 1 n-1 n−1中必定存在拐点,即局部最小值。
这时候发现一个性质:
当一个区间 [ l , r ] [l, r] [l,r]左右皆呈向中间下降的趋势的时候,区间一定存在局部最小值。
不难想到在该区间中(不包含端点)任取一点 p o s pos pos,该点要么是局部最小值,否则它一定存在一个相邻点比它小,假设 a [ p o s − 1 ] < a [ p o s ] a[pos - 1] < a[pos] a[pos−1]<a[pos],那么 [ l , p o s ] [l, pos] [l,pos] 便可作为一个新的区间,便可缩小区间范围,至于这个 p o s pos pos 怎么取很明显可以二分。
注意特判 n = 1 n = 1 n=1 的情况
- 代码
#include <bits/stdc++.h>
const int N = 1e5 + 10;
typedef long long ll;
using namespace std;
void solve()
{
}
int main()
{
int n;
cin>>n;
int l=1,r=n;
int arr[n+1]={0};
if(n==1)
{
cout<<"! "<<1<<endl;
return 0;
}
cout << "? " << l << endl;
cout.flush();
cin >> arr[l];
cout << "? " << r << endl;
cout.flush();
cin >> arr[r];
while(l<r)
{
int mid=l+r>>1;
if(arr[mid]==0)
{
cout<<"? "<<mid<<endl;
cout.flush();
cin>>arr[mid];
}
if(arr[mid+1]==0)
{
cout<<"? "<<mid+1<<endl;
cout.flush();
cin>>arr[mid+1];
}
if(arr[mid]<arr[mid+1])
r=mid;
else
{
l=mid+1;
}
}
cout<<"! "<<l<<endl;
cout.flush();
}