题解
题目大意 n个点组成一个环形 初始钱为m 从i走到j需要-b[i] + a[j] 要求按照顺时针走完所有的点(不用再回到起点) 过程中m不能小于0 输出最小的起点编号
直接把a[i]和b[i]合在一起 看作到达这个点会增加的值 起点先算一次 做一次前缀和并且增长一倍记为s i枚举1到n为起点 用ST表求i到i+n-1区间的最小值-s[i - 1]+m如果大于等于0则满足条件
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 2e6 + 10;
ll a[MAXN];
ll pw2[30], lg2[MAXN], mn[30][MAXN];
void getst(int n) //nlogn初始化st表 不可修改
{
for (int i = 1; i <= n; i++)
mn[0][i] = a[i]; //i到i+2^0-1就一个位置 最值等于自己本身
for (int i = 1; i <= lg2[n]; i++)
for (int j = 1; j + pw2[i] - 1 <= n; j++) //区间末尾不超过n
mn[i][j] = min(mn[i - 1][j], mn[i - 1][j + pw2[i - 1]]); //max/min
}
ll ask(int l, int r)
{
int w = lg2[r - l + 1]; //x >= 2^lg2(x) > x/2 从两端长度为pw2[x]一定会覆盖整个区间而又不会超出区间
return min(mn[w][l], mn[w][r - pw2[w] + 1]); //max/min
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
pw2[0] = 1, lg2[0] = -1;
for (int i = 1; i < 30; i++)
pw2[i] = pw2[i - 1] << 1;
for (int i = 1; i < MAXN; i++)
lg2[i] = lg2[i >> 1] + 1;
int T;
cin >> T;
while (T--)
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
int t;
scanf("%d", &t);
a[i] = t;
}
for (int i = 1; i <= n; i++)
{
int t;
scanf("%d", &t);
a[i] -= t;
}
for (int i = 1; i <= n; i++)
a[i + n] = a[i];
for (int i = 1; i <= n * 2; i++)
a[i] += a[i - 1];
getst(n * 2);
int ans = INF;
for (int i = 1; i <= n; i++)
{
ll res = ask(i, i + n - 1);
res = res - a[i - 1] + m;
if (res >= 0)
{
ans = i;
break;
}
}
if (ans != INF)
cout << ans << endl;
else
cout << -1 << endl;
}
return 0;
}
补一个更短的算法 尺取法
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 2e6 + 10;
ll a[MAXN];
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int T;
cin >> T;
while (T--)
{
int n;
ll c;
cin >> n >> c;
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for (int i = n + 1; i <= n * 2; i++) //合并ab数组 并延长一倍
scanf("%lld", &a[i]), a[i - n] -= a[i], a[i] = a[i - n];
int l = 1, r = 1;
while (l <= n && r - l + 1 <= n) //l循环一个n 区间长度大于n则满足条件
{
c += a[r++]; //加当前r 后移
while (c < 0) //如果小于0则区间不满足 l后移
c -= a[l++]; //并减去l
}
if (l <= n)
cout << l << endl;
else
cout << -1 << endl;
}
return 0;
}