看到题目我首先想到了之前做过的一道题
二分+树状数组解决中位数问题
按照同样的思路迅速码了,提交TLE+WA,于是开始怀疑人生
确认一下树状数组的时间复杂度:
对含有n个元素的数组 a [ 1 ] , . . . , a [ k ] , . . . , a [ n ] a[1],...,a[k],...,a[n] a[1],...,a[k],...,a[n]:
- 求出第 i i i个到第 j j j个元素的和, s u m = a [ i ] + . . . + a [ j ] sum=a[i]+...+a[j] sum=a[i]+...+a[j]
进行 j − i + 1 j-i+1 j−i+1次加法,复杂度为 O ( n ) O(n) O(n)- 任意修改其中某个元素的值
使用数组下标可以直接定位修改,时间复杂度为 O ( 1 ) O(1) O(1)- 如果系统中大量进行上述两种操作 m m m次,其中执行区间和查询操作的概率为 1 / p 1/p 1/p,执行修改操作的概率为 1 − 1 / p 1-1/p 1−1/p,则系统时间复杂度为 O ( m n ) O(mn) O(mn)
- 使用树状数组使得上述两种操作的时间复杂度为 O ( m ∗ l o g n ) O(m*logn) O(m∗logn)
从复杂度上看,没有道理又WA又TLE
那么问题只有可能出现在二分算法上
删除二分后,第三个点TLE
俗话说的好:TLE比WA更致命,TLE基本上意味着重构代码
我们推翻之前的思路,重新观察数据的特点
将
n
n
n个数据从大到小排序,根据排序后的数组可得知大于等于
a
[
i
]
a[i]
a[i]的天数有
i
i
i天
题目中要求超过E英里且所有的英里数为整数,可得大于
a
[
i
]
−
1
a[i]-1
a[i]−1的天数有
i
i
i天
根据题意,我们需要让
i
>
=
a
[
i
]
−
1
i>=a[i]-1
i>=a[i]−1
第一个实现以上条件的
a
[
i
]
−
1
a[i]-1
a[i]−1即为答案
TLE+WA代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int N = 100010;
int n;
int c[N];
int lowbit(int x) { return x & (-x); }
void insert(int x) {
while (x < 100000) {
c[x]++;
x += lowbit(x);
}
}
int sum(int x) {
int ans = 0;
while (x) {
ans += c[x];
x -= lowbit(x);
}
return n - ans;
}
int erfen() {
int l = 0;
int r = 100000;
int m;
while (l < r - 1) {
m = (l + r) / 2;
int t = sum(m);
if (t < m) r = m;
else l = m;
}
return l;
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
int x;
scanf("%d", &x);
insert(x);
}
printf("%d", erfen());
return 0;
}
TLE代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int N = 100010;
int n;
int c[N];
int lowbit(int x) { return x & (-x); }
void insert(int x) {
while (x < 100000) {
c[x]++;
x += lowbit(x);
}
}
int sum(int x) {
int ans = 0;
while (x) {
ans += c[x];
x -= lowbit(x);
}
return n - ans;
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
int x;
scanf("%d", &x);
insert(x);
}
for (int i = n; i >= 0; i--) {
if (sum(i) >= i) {
printf("%d",i);
break;
}
}
return 0;
}
AC代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100010;
int n;
int a[N];
int cmp(const int a,const int b) {
return a > b;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <=n; ++i) {
if (i >= a[i] - 1) {
printf("%d",a[i]-1);
break;
}
}
return 0;
}