Maximum Sequence
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
Problem Description
Steph is extremely obsessed with “sequence problems” that are usually seen on magazines: Given the sequence 11, 23, 30, 35, what is the next number? Steph always finds them too easy for such a genius like himself until one day Klay comes up with a problem and ask him about it.
Given two integer sequences {ai} and {bi} with the same length n, you are to find the next n numbers of {ai}: an+1…a2n. Just like always, there are some restrictions on an+1…a2n: for each number ai, you must choose a number bk from {bi}, and it must satisfy ai≤max{aj-j│bk≤j
Input
The input contains no more than 20 test cases.
For each test case, the first line consists of one integer n. The next line consists of n integers representing {ai}. And the third line consists of n integers representing {bi}.
1≤n≤250000, n≤a_i≤1500000, 1≤b_i≤n.
Output
For each test case, print the answer on one line: max{∑2nn+1ai} modulo 109+7。
Sample Input
4
8 11 8 5
3 1 4 2
Sample Output
27
Hint
For the first sample:
1. Choose 2 from {bi}, then a_2…a_4 are available for a_5, and you can let a_5=a_2-2=9;
2. Choose 1 from {bi}, then a_1…a_5 are available for a_6, and you can let a_6=a_2-2=9;
题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=6047
分析
题意:给出两个长度为n的数组a,b,下标为1到n,给定a[n]到a[2n]满足的关系式 a[i]≤max{a[j]-j│b[k] ≤ j < i},现在要计算a[n]到a[2n]的总和的最大值,其中b中的元素每个只能用一次
由关系式可以知道a[i]{ i | n < i ≤ 2n }的值为a[b[k]]-b[k]到a[i-1]-(i-1)的最大值,所以b的值直接按照从小到大的顺序使用就可以了,可以用线段树来做,也可以直接循环嵌套来做
代码
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
#define MAXN 500050
#define ll long long
using namespace std;
const int MOD=1e9+7;
int main()
{
int n;
ll d[MAXN];///存放a[b[k]]到a[i-1]的最大值
while(~scanf("%d",&n))
{
ll a[MAXN];
int c,b[MAXN];
memset(d,0,sizeof(d));
a[0]=0;
b[0]=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&c);
a[i]=c-i;///直接存放a[i]-i的值
}
for(int i=1; i<=n; i++)
{
scanf("%d",&b[i]);
}
sort(b+1,b+n+1);///将b排序,下标从1开始到n
int y=n,k=1,i=0,pos;
ll sum=0;///由于结果可能非常大,所以用long long,否则会WA掉
while(y<2*n)///当y>=2*n时,说明已经a[n]到a[2n]的值已全部算出
{
if(i>n&&a[i]<d[b[k-1]]&&b[k]<=pos)
///如果循环不是第一次,则a中已经插入了新的值,需要比较新的值与之前的最大值的大小
///如果之前的最大值的位置pos在新的b[k]之后,则最大值可以不变,直接赋给新的d[b[k]]
///用这个判断可以减少好多次后面的循环,节省好多时间,否则会时间超限
d[b[k]]=d[b[k-1]];
else for(i=b[k]; i<=y; i++)///循环来得到a[b[k]]到a[i]的最大值
{
d[b[k]]=max(d[b[k]],a[i]);
if(d[b[k]]==a[i])pos=i;///记录最大值的下标
}
i=y+1;
a[i]=d[b[k]]-i;///将得到的值减去它的下标存到a数组中
sum=(sum+d[b[k]])%MOD;///将得到的a[i]的值加入总和,并每次都取余
k++;///b[k]的值只能使用一次,所以k++
y++;///将需要取最大值的区间的右边界加1,来将新加入的值包含到区间内
}
printf("%lld\n",sum);
}
}