HDU 6047 Maximum Sequence(贪心+线段树)

题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=6047

题目:

Maximum Sequence

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 90    Accepted Submission(s): 44


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+1a2n. Just like always, there are some restrictions on an+1a2n: for each number ai, you must choose a number bk from {bi}, and it must satisfy ai≤max{aj-j│bk≤j<i}, and any bk can’t be chosen more than once. Apparently, there are a great many possibilities, so you are required to find max{2nn+1ai} modulo 109+7 .

Now Steph finds it too hard to solve the problem, please help him.

 

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
 

多校联赛第二场~

题意:

给定一个长度为n的a数组和b数组,要求a[n+1]…a[2*n]的最大总和。 限制条件为ai≤max{aj-j│bk≤j<i}。

 

思路:

a[j](j>n)是从当前选择的a数组的b[k]个数开始,到最后一个数中选。由于每个b[k]都只能使用一次,我们要可能地把b[k]较大的数留在后面用,因为刚开始a数组只有n个,只有随着每次操作a数组才会增加一个数。

顺着这个思路,我们很自然地先对b数组做一次升序排序,再以b[k]为左区间,a数组当前的个数为右区间,来找最大的a[j]; 因为数据量比较大,我们经常要获取某个区间a[j]的最大值,所以用线段树维护。

 

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 const int N=250000*2+5;
 7 const int M= 1e9+7;
 8 typedef long long ll;
 9 struct node{
10     int l,r;
11     int Max;
12     ll  sum;
13 }tree[4*N];
14 int n;
15 int a[N],b[N];
16 void pushup(int i){
17     tree[i].sum=(tree[2*i].sum+tree[2*i+1].sum)%M;//别忘了mod运算
18     tree[i].Max=max(tree[2*i].Max,tree[2*i+1].Max);
19 }
20 void build(int l,int r,int i){
21     if(i>8*n)   return ;
22     tree[i].l=l;
23     tree[i].r=r;
24     if(tree[i].l==tree[i].r) {
25         if(l>n){
26             tree[i].sum=0;
27             tree[i].Max=0;
28         }else{
29             tree[i].sum=a[l];
30             tree[i].Max=a[l]-l;//MAX存的是a[j]-j;
31         }
32         return ;
33     }
34     int mid=(l+r)/2;
35     build(l,mid,2*i);
36     build(mid+1,r,2*i+1);
37     pushup(i);//回溯更新父节点
38 }
39 void update(ll v,int x,int i){
40     if(tree[i].l==tree[i].r){
41         tree[i].sum=v;
42         tree[i].Max=v-x;
43         return ;
44     }
45     int mid=(tree[i].l+tree[i].r)/2;
46     if(x<=mid)  update(v,x,2*i);
47     else update(v,x,2*i+1);
48     pushup(i);
49 }
50 int query(int l,int r,int i){
51     if(tree[i].l==l && tree[i].r==r)    return tree[i].Max;
52     int mid=(tree[i].l+tree[i].r)/2;
53     if(r<=mid)  return query(l,r,2*i);
54     else if(l>mid)  return query(l,r,2*i+1);
55     else if(l<=mid && r>mid)    return max(query(l,mid,2*i),query(mid+1,r,2*i+1));
56     return -1;
57 }
58 int main(){
59     while(scanf("%d",&n)!=EOF){
60         int pre=0;
61         for(int i=1;i<=n;i++)   scanf("%d",&a[i]);
62         for(int i=0;i<n;i++)    scanf("%d",&b[i]);
63         build(1,2*n,1);
64         sort(b,b+n);
65         for(int i=n+1;i<=2*n;i++){
66             int x,y;
67             int bg,ed=i-1;
68             x=bg=b[pre++];//排序完直接按顺序取b数组,保证了不会重复使用
69             y=query(bg,ed,1);
70             a[i]=max(x,y);
71             update(a[i],i,1);
72         }
73         printf("%lld\n",tree[3].sum);//tree[3]保存的是n+1…2*n的节点信息
74     }
75     return 0;
76 }

 

posted @ 2017-07-27 18:30  ventricle  阅读(523)  评论(0编辑  收藏  举报