然而,即使使用了二分,程序依然不能通过所有数据。因为我们忘了题目中的一个条件——区间总数上限是200000,而不同区间可能重合或相互重叠,所以,如果我们仅仅按照题目描述的方式计算每个区间上的Yi,那么在最坏情况仅仅计算所有区间上的Y就会超时,因此,需要一个更巧妙的方法——前缀和,实现方式请看代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MXN 200000+1
long cnt[MXN];
unsigned long long sum[MXN],s;
long w[MXN],v[MXN];
long m,n;
long range_l[MXN],range_r[MXN];
long long calc_range(long l,long r)
{
return (cnt[r] - cnt[l - 1]) * (sum[r] - sum[l - 1]);
}
long long calc_tot(long lim)
{
long long res = 0;
long i;
//空间换时间
cnt[0] = 0;
sum[0] = 0;
for(i = 1;i <= n;i ++)
{
cnt[i] = cnt[i - 1];
sum[i] = sum[i - 1];
if(w[i] >= lim)
{cnt[i] += 1;sum[i] += v[i];}
}
for(i = 0;i < m;i ++)
res += calc_range(range_l[i],range_r[i]);
return res;
}
int main()
{
long i;
long long a,b;
scanf("%ld%ld%lld",&n,&m,&s);
for(i = 1;i <= n;i ++)
scanf("%ld%ld",&w[i],&v[i]);
for(i = 0;i < m;i ++)
scanf("%ld%ld",&range_l[i],&range_r[i]);
long l,r,mid;
//分别从两个方向逼近S
l = 0;r = 10e6 + 1;
while(l < r)
{
mid = (l + r) / 2;
if(calc_tot(mid) <= s)
r = mid;
else
l = mid + 1;
}
a = llabs(calc_tot(l) - s);
l = 0;r = 10e6 + 1;
//其实这里的l,r没有必要开这么大,读者可以自行分析
while(l < r)
{
mid = (l + r + 1) / 2;
if(calc_tot(mid) >= s)
l = mid;
else r = mid - 1;
}
b = llabs(calc_tot(l) - s);
if(a < b) printf("%lld\n",a);
else printf("%lld\n",b);
return 0;
}
#include <stdlib.h>
#include <string.h>
#define MXN 200000+1
long cnt[MXN];
unsigned long long sum[MXN],s;
long w[MXN],v[MXN];
long m,n;
long range_l[MXN],range_r[MXN];
long long calc_range(long l,long r)
{
return (cnt[r] - cnt[l - 1]) * (sum[r] - sum[l - 1]);
}
long long calc_tot(long lim)
{
long long res = 0;
long i;
//空间换时间
cnt[0] = 0;
sum[0] = 0;
for(i = 1;i <= n;i ++)
{
cnt[i] = cnt[i - 1];
sum[i] = sum[i - 1];
if(w[i] >= lim)
{cnt[i] += 1;sum[i] += v[i];}
}
for(i = 0;i < m;i ++)
res += calc_range(range_l[i],range_r[i]);
return res;
}
int main()
{
long i;
long long a,b;
scanf("%ld%ld%lld",&n,&m,&s);
for(i = 1;i <= n;i ++)
scanf("%ld%ld",&w[i],&v[i]);
for(i = 0;i < m;i ++)
scanf("%ld%ld",&range_l[i],&range_r[i]);
long l,r,mid;
//分别从两个方向逼近S
l = 0;r = 10e6 + 1;
while(l < r)
{
mid = (l + r) / 2;
if(calc_tot(mid) <= s)
r = mid;
else
l = mid + 1;
}
a = llabs(calc_tot(l) - s);
l = 0;r = 10e6 + 1;
//其实这里的l,r没有必要开这么大,读者可以自行分析
while(l < r)
{
mid = (l + r + 1) / 2;
if(calc_tot(mid) >= s)
l = mid;
else r = mid - 1;
}
b = llabs(calc_tot(l) - s);
if(a < b) printf("%lld\n",a);
else printf("%lld\n",b);
return 0;
}
No comments:
Post a Comment