数列要满足aj <= max{ai - i},其中bk <= j < i,bk是数列b中的一项,且每个bk最多仅能取一次
看到这里肯定还看不明白。
具体说一下第一个样例:
a数组是8 11 8 5 b数组是3 1 4 2
现在要扩充a数组,然后数组的扩充方法是,a数组中每个数等于本身减去他的下标,然后从b数组中选一个数,然后a数组的这个数的位置开始到最后选一个最大的(只能解释到这样了)。
实现:a数组相当于 (8-1)(11-2)(8-3)(5-4)
从b数组中选择1,代表从a[1]到a[4]中选择一个最大的,选择9。然后将9添加到a数组中,然后数组为(8-1)(11-2)(8-3)(5-4) (9-5)
然后第二次从b数组中选择2代表从a[2]到a[5]中选择一个最大的,选择9。然后将9添加到a数组中,然后数组为(8-1)(11-2)(8-3)(5-4) (9-5)(9-6)
然后第三次从b数组中选择3代表从a[3]到a[6]中选择一个最大的,选择5。然后将5添加到a数组中,然后数组为(8-1)(11-2)(8-3)(5-4) (9-5)(9-6)(5-7)
然后第四次从b数组中选择4代表从a[4]到a[7]中选择一个最大的,选择4。然后将9添加到a数组中,然后数组为(8-1)(11-2)(8-3)(5-4) (9-5)(9-6)(5-7)(4-8)
然后更新完成了。最后数列a的n+1到2*n项的值为9+9+5+4=27
思路:
要想使数列a的n+1到2*a项最大,又每项都要减去i
所以应该尽量使bk最小,从最前面开始(可以理解为贪心)
那么肯定要先把最大的放进来
将b排序,计算ai - i的值
开一个max数组记录从i 到最后一项的最大ai-i的值(可以从后往前找)
每次加入点的时候,从后往前比较,如果小于这个数,就更新为这个数。
用一个sum记录总和。
记得每次加的结果要%mod。
注意数组要开为数据量的两倍,因为a数组要扩展!
C++ Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> int mod=1e9+ 7 ; using namespace std; int a[ 500010 ],b[ 500010 ],maxx[ 500010 ]; int main() { int n; while (~scanf( "%d" ,&n)) { memset(maxx, 0 , sizeof (maxx)); for ( int i= 1 ; i<=n; i++) { scanf( "%d" ,a+i); a[i]-=i; } for ( int i= 1 ; i<=n; i++) { scanf( "%d" ,b+i); } sort(b+ 1 ,b+n+ 1 ); maxx[n]=a[n]; for ( int i=n; i>= 2 ; i--) //更新max数组 { maxx[i- 1 ]=max(a[i- 1 ],maxx[i]); } int flag=n+ 1 ; int sum= 0 ; for ( int i= 1 ; i<=n; i++) { sum+=maxx[b[i]]; //选择最大的数 a[flag]=maxx[b[i]]-(flag); maxx[flag]=a[flag]; for ( int j=flag- 1 ; j>= 1 ; j--) //加入新的点之后,要更新对应的max { if (maxx[j]<maxx[flag]) maxx[j]=maxx[flag]; else break ; } flag++; sum=sum%mod; } printf( "%d\n" ,sum); } }