2017 ACM/ICPC Asia Regional Shenyang Online
题意:
给定数列a,b,它们都有n个数,保证a数列的和等于b数列的和,计算a[i]-b[i]的前缀和c[i]。i从1到n,如果c[i]大于等于0,则可以往下继续取,否则停止,取得的结果是停止时的i或者n。但有一个操作,就是把第一组(a[1],b[1])移至末尾,后面的元素都向前一位,问进行若干操作之后能够取得的最大值时需要的最小操作数。
思路:
由于保证a数列的和等于b数列的和,所以可以模拟一下不管怎么排列,最终能取得的最大值肯定是n。很容易知道当前排列可行的条件是每一个前缀和都>=0,操作其实也可以看成选定一个i,把从1..i的所有位平移至末尾,所以我们贪心地从第一位开始向后,如果把1..i位平移至末尾能导致所有前缀和都>=0则立即停止,i即是答案。假设此时我们在点i,如果i+1..n之间的前缀和最小值减去前缀和c[i]之后>=0,则表明将1..i这一块移到末尾能导致i+1..n位所有的前缀和>=0,再如果1..i之间的前缀和最小值加上前缀和c[n]-c[i]之后>=0,则表明将1..i这一块移到末尾能导致1..i位所有的前缀和>=0,从而我们得到了解决方案。寻找区间内前缀和最小值只能根据线段树,RMQ空间会爆。
代码(其实不用fastIO也能过):
#include <bits/stdc++.h>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
namespace fastIO
{
#define BUF_SIZE 100000
//fread -> read
bool IOerror = 0;
inline char nc()
{
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if(p1 == pend)
{
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pend == p1)
{
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch)
{
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline void read(int &x)
{
char ch;
while(blank(ch = nc()));
if(IOerror) return;
for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1e6+5;
int n, ans;
int a[maxn], b, c[maxn];
int tree[maxn<<2];
void push_up(int rt){tree[rt] = min(tree[rt<<1], tree[rt<<1|1]);}
void build(int l, int r, int rt)
{
if(l == r)
{
tree[rt] = c[l];
return;
}
int m = (r+l)>>1;
build(lson); build(rson);
push_up(rt);
}
int query(int L, int R, int l, int r, int rt)
{
if(l <= L && R <= r) return tree[rt];
int m = (l+r)>>1, res = inf;
if(L <= m) res = min(res, query(L, R, lson));
if(R > m) res = min(res, query(L, R, rson));
}
int main()
{
while(read(n), !IOerror)
{
for(int i = 1; i <= n; ++i) read(a[i]);
for(int i = 1; i <= n; ++i)
{
read(b);
c[i] = c[i-1] + a[i]-b;
}
build(1, n, 1);
int pre = inf;
for(int i = 0; i < n; ++i)
{
int tmp = query(i+1, n, 1, n, 1);
if(tmp-c[i] >= 0 && c[n]-c[i]+pre >= 0)
{
ans = i; break;
}
else pre = min(pre, c[i+1]);
}
printf("%d\n", ans);
}
return 0;
}
继续加油~