HDU 6047 Maximum Sequence(贪心+线段树)
Posted ventricle
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
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<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.
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.
多校联赛第二场~
题意:
给定一个长度为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 ll Max,sum; 12 }tree[4*N]; 13 struct edge{ 14 int id; 15 int v; 16 bool operator <(const edge &x) const{ 17 return v<x.v; 18 } 19 }; 20 int n; 21 ll a[N]; 22 vector<edge>b; 23 void pushup(int i){ 24 tree[i].sum=(tree[2*i].sum+tree[2*i+1].sum)%M;//别忘了mod运算 25 tree[i].Max=max(tree[2*i].Max,tree[2*i+1].Max); 26 } 27 void build(int l,int r,int i){ 28 if(i>8*n) return ; 29 tree[i].l=l; 30 tree[i].r=r; 31 if(tree[i].l==tree[i].r) { 32 if(l>n){ 33 tree[i].sum=0; 34 tree[i].Max=0; 35 }else{ 36 tree[i].sum=a[l]; 37 tree[i].Max=a[l]-l;//MAX存的是a[j]-j; 38 } 39 return ; 40 } 41 int mid=(l+r)/2; 42 build(l,mid,2*i); 43 build(mid+1,r,2*i+1); 44 pushup(i);//回溯更新父节点 45 } 46 void update(ll v,int x,int i){ 47 if(tree[i].l==tree[i].r){ 48 tree[i].sum=v; 49 tree[i].Max=v-x; 50 return ; 51 } 52 int mid=(tree[i].l+tree[i].r)/2; 53 if(x<=mid) update(v,x,2*i); 54 else update(v,x,2*i+1); 55 pushup(i); 56 } 57 ll query(int l,int r,int i){ 58 if(tree[i].l==l && tree[i].r==r) return tree[i].Max; 59 int mid=(tree[i].l+tree[i].r)/2; 60 if(r<=mid) return query(l,r,2*i); 61 else if(l>mid) return query(l,r,2*i+1); 62 else if(l<=mid && r>mid) return max(query(l,mid,2*i),query(mid+1,r,2*i+1)); 63 } 64 int main(){ 65 while(scanf("%d",&n)!=EOF){ 66 int pre=0; 67 b.clear(); 68 for(int i=1;i<=n;i++){ 69 scanf("%I64d",&a[i]); 70 } 71 build(1,2*n,1); 72 for(int i=1;i<=n;i++){ 73 edge x; 74 scanf("%d",&x.v); 75 x.id=i; 76 b.push_back(x); 77 } 78 sort(b.begin(),b.end()); 79 for(int i=n+1;i<=2*n;i++){ 80 ll x,y; 81 int bg,ed=i-1; 82 x=bg=b[pre++].v;//排序完直接按顺序取b数组,保证了不会重复使用 83 y=query(bg,ed,1); 84 a[i]=max(x,y); 85 update(a[i],i,1); 86 } 87 printf("%I64d\n",tree[3].sum);//tree[3]保存的是n+1…2*n的节点信息 88 } 89 return 0; 90 }
以上是关于HDU 6047 Maximum Sequence(贪心+线段树)的主要内容,如果未能解决你的问题,请参考以下文章
HDU 6047 17多校 Maximum Sequence(优先队列)
HDU 6047 Maximum Sequence (贪心+单调队列)
多校训练2HDU 6047 Maximum Sequence