【题目来源】:http://acm.hdu.edu.cn/showproblem.php?pid=6047
【题意】
给出序列a和序列b,均有n项,让求后n项的最大和。
并且给出了一个关系,是a[x] =max( a[j]-j),(b[k]<=j小于i)
我的理解是:因为b[k]是只能用一次的,所以,就使得a[j]-j这个式子的最大值要多次利用,怎么才能多次利用呢?就要考虑到b[k]对a[j]取值的影响。
比如样例:
8 11 8 5
3 1 4 2
这里,第一步取b数组中的2,所以a[2]…a[4]都可以用,但是当然要取最大值,所以取出11-2,也就是a[5]=9,
第二部取b数组中的1,此时,a[1]..a[5]都可以用,当然,虽然加了a[5],但是a[2]-2依旧是最大,所以使用。
也就是说,要使得最大的值尽可能多次利用,就是解决本题的关键。
//利用优先队列每次挑出最大值,根据他对应的j去处理对应的b[k]
#include<map>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
typedef long long LL;
int b[250000+10];
int w[250000+10];
struct pp
{
int index;
int ans;
}a[250000+10];
struct cmp
{
bool operator()(pp s,pp t)
{
if(s.ans==t.ans)
return s.index>t.index;
return s.ans<t.ans;
}
};
priority_queue<pp,vector<pp>,cmp> q;
int main()
{
int n;
while(~scanf("%d",&n))
{
while(!q.empty()) q.pop();
for(int i=1;i<=n;i++)
{
a[i].index=i;
scanf("%d",&a[i].ans);
a[i].ans-=i;
q.push(a[i]);
}
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
memset(w,0,sizeof(w));
for(int i=1;i<=n;i++)
w[b[i]]++;
LL sum=0;
int pos=n;
int d_m=0;
while(1)
{
pp T_T=q.top();
q.pop();
LL num=0;
if(T_T.index<=d_m) continue;
else
{
for(int i=d_m+1;i<=T_T.index;i++)
num+=w[i];
d_m=T_T.index;
}
sum+=(num*T_T.ans)%mod;
sum%=mod;
pp x_s;
x_s.index=pos+1;
x_s.ans=T_T.ans-pos-1;
q.push(x_s);
pos+=num;
if(pos==2*n) break;
}
printf("%lld\n",sum);
}
}