题意:找到第一个不满足分配的订单编号
一般可以先通过暴力的方法来寻找思路,我们要找左侧第一个点,左侧边界
那么先对编号数组进行二分
while(l<r)
{
int mid=l+r>>1;
if(check())
r=mid;
else
l=mid+1;
}
check表示当前不满足条件 ,就可以向左侧二分,找到第一个点
我们发现,每一个订单都是对于区间操作
开始~结束 都-=要租借的订单数
所以自然可以想到差分的操作,对区间修改,最后运用前缀和求某一个特定的点的值
1.附上代码O(nlogn)
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6+5;
int a[N];
int b[N];
struct node
{
int d;
int st, ed;
}t[N];
int n, m;
//前缀和:减小对区间查询的时间复杂度
bool check(int x)
{
for (int i = 1;i <= n;i++)
b[i] = a[i] - a[i - 1];
for (int i = 1;i <= x;i++)
{
b[t[i].st] -= t[i].d;
b[t[i].ed + 1] += t[i].d;
}
for (int i = 1;i <= n;i++)
{
b[i] += b[i - 1];
if (b[i] < 0) return true;
}
return false;
}
int main()
{
cin >> n >> m;
for (int i = 1;i <= n;i++)
cin >> a[i];
for (int i = 1;i <= m;i++)
cin >> t[i].d >> t[i].st >> t[i].ed;
int l = 0, r = m;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid))
r = mid; //如果分配失败,往左走
else //分配成功,往右走
l = mid + 1;
}
if (check(l))
cout << -1 << endl << l;
else
cout << 0;
return 0;
}
这里提一下为什么要进行二分
如果,我们直接枚举,时间复杂度是O(n^2),如果运用差分优化之后,尽管每次修改的时间复杂度仅为O(1),但是我们本题是要求哪一个是第一个不满足条件的订单,这样子每一个订单修改区间后都需要查询有没有小于0,时间复杂度又变成O(n^2),所以需要二分,时间复杂度是O(nlogn)
2.优化后的二分答案,时间复杂度无限接近于O(n+logn)
#include <cstdio>
#include <iostream>
#include <cstdlib>
using namespace std;
const int maxn = 1000005;
int n, m, ans = 20021228;
int r[maxn], c[maxn], now;
int d[maxn], s[maxn], t[maxn];
bool check(int mid) //判断当前的二分值是否可行
{
int i, sum = 0;
if(now > mid)
for(i = mid + 1; i <= now; i++) {
c[s[i]] -= d[i];
c[t[i] + 1] += d[i];
}
else
for(i = now + 1; i <= mid; i++) { //注意这里是将以前操作的恢复原样,操作相反
c[s[i]] += d[i];
c[t[i] + 1] -= d[i];
}
now = mid;
for(i = 1; i <= n; i++) {
sum += c[i];
if(sum > r[i]) return true;
}
return false;
}
int main()
{
int i;
scanf("%d%d", &n, &m);
for(i = 1; i <= n; i++)
scanf("%d", &r[i]);
for(i = 1; i <= m; i++) {
scanf("%d%d%d", &d[i], &s[i], &t[i]);
}
int l = 1, r = m, mid;
while(l <= r) { //二分答案
mid = (l + r) / 2;
if(check(mid)) ans = min(ans, mid), r = mid -1;
else l = mid + 1;
}
if(ans != 20021228)
printf("-1\n%d", ans);
else printf("0");
return 0;
}
3.暴力枚举 O(n^2)
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100005;
int a[N];
int q[N];
struct node
{
int d;
int st, ed;
}t[N];
void print(int i)
{
cout << -1 << '\n';
cout << i;
}
/*暴力的做法:我们发现,找到第一个会让等式不满足的点就可以了*/
int main()
{
int n,m;
cin >> n>>m;
for (int i = 1;i <= n;i++)
cin >> a[i];
for (int i = 1;i <= m;i++)
cin >> t[i].d >> t[i].st >> t[i].ed;
bool flag = false;
for (int i = 1;i <= m;i++)
{
node k = t[i];//某个订单
for (int j = k.st;j <= k.ed;j++)
{
a[j] -= k.d;
if (a[j] < 0)
{
flag = true;
print(i);break;
}
}
if (flag) break;
}
if (flag)
return 0;
else
cout << 0;
}