2017 Multi-University Training Contest - Team 2 Maximum Sequence

这个题目简单的贪心即可(后面附上官方证明),实现起来要注意ai数组要不断更新,b数组排序后从头往后依次使用即可。

官方证明:预处理:a_i -= i ,易证明从最小的b开始选每次选最大的一定可以使结果最大。 证明思路:如果条件改为a_i<=max{a_j-j|b_k<=j<=n},那么b的顺序与最后的结果无关。条件改回来后,由于每次要计算一个数的最大值时都有a_(n+1)...a_(i-1)在范围中,所以每次只需让a_i - i尽可能大,那么就把大的数尽早用上,每次一定考虑尽量多的数字,这样取得的数字就尽可能的大。 所以说每次就是求区间最值,加在答案上。由于贪心的思路,每次要求的区间的下界是单调不降的,故可以用单调队列优化到O(n)的复杂度。 由于1 ≤ b_i ≤ n,对b排序可以用哈希排序(桶排序)完成。进一步观察,可以发现这样贪心时 a_(n+1)...a_i 其实是单调不增的,所以并不需要每次求区间最值了,选第一个数时就选最大的,后面的选择顺序与最终结果无关了。

        #include<iostream>
        #include<cstdio>
        #include<algorithm>
        using namespace std;
        
        const int maxx=250010;
        int a[2*maxx],b[2*maxx];
		int as[2*maxx];
        
        int main()
{  
        int n;
        while(scanf("%d",&n)==1)
        {
        	for(int i=1;i<=n;i++)
        	{
        		scanf("%d",&a[i]);
        		as[i]=a[i]-i;
			}
			
			for(int i=1;i<=n;i++)
        	{
        		scanf("%d",&b[i]);
			}
			
			int Max=as[n];
			for(int i=n;i>=1;i--)
			{
				if(as[i]>Max)
				{
					Max=as[i];
				}
				else
				{
					as[i]=Max;
				}
			}
			
			sort(b+1,b+n+1);
			int pos=1;
			long long ans=0;
			
			for(int i=n+1;i<=2*n;i++)
			{
				a[i]=as[b[pos++]];
				//cout<<"b[pos="<<b[pos]<<endl;
				//cout<<"ai="<<a[i]<<endl;
				ans+=a[i];
				ans%=1000000007;
				
				as[i]=a[i]-i;
				int j=i;
				while(j>=1&&as[j]>as[j-1])
				{
					as[j-1]=as[j];
					j--;
				}
			}
			//cout<<ans;
			printf("%lld\n",ans);
		}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值