[找规律]Array Concatenation 2022年CCPC桂林站C

59 篇文章 0 订阅

Little relyt871 has a magical machine. In each operation, his machine can do one of the following operations to the input array bb:

  • Generate a copy of bb and concatenate it after bb. More formally, the resulting array should be

    b′={b1,b2,…,b|b|,b1,b2,…,b|b|}.b′={b1,b2,…,b|b|,b1,b2,…,b|b|}.

  • Generate a copy of bb, reverse it, then concatenate it before bb. More formally, the resulting array should be

    b′={b|b|,b|b−1|,…,b1,b1,b2,…,b|b|}.b′={b|b|,b|b−1|,…,b1,b1,b2,…,b|b|}.

Initially, he has an array aa of length nn. Then, he wants to operate the machine exactly mm times using the array on his hand while maximizing the sum of all prefix sums of the final array. Since he has a somewhat finite brain, when he adds some integers, he only cares about the sum modulo 10000000071000000007. Formally, suppose after all mm operations he has array bb of length n′n′, he wants to maximize the following value:

(∑i=1n′∑j=1ibj)(mod1000000007).(∑i=1n′∑j=1ibj)(mod1000000007).

Please note that you should maximize the value after taking the modulo: the array with answer 10000000071000000007 before taking the modulo is considered less than the array with answer 11.

Input

The first line contains two integers nn and mm (1≤n,m≤1051≤n,m≤105).

The second line contains nn integers a1, a2,..., ana1, a2,..., an (1≤ai≤1091≤ai≤109) separated by spaces.

Output

Print a single integer in one line, denoting the answer.

Examples

input

2 1
1 2

output

15

input

5 10
26463 39326 86411 75307 85926

output

806275469

题意: 有一个长度为n的数组,还有m次操作,每次操作可以选择将数组copy一份拼接到原数组后面作为新数组,或者将数组copy一份拼接到翻转后的数组后面作为新数组。问经过恰好m次操作后,最终数组的前缀和数组的和在模1e9+7下的最大值。

分析: 模拟一下发现当进行一次翻转后之后得到的数组都完全相同,于是可以根据这个性质枚举第几次翻转,然后统计答案。再进一步分析可以发现无论第几次翻转最终答案都不变,这是因为把两个第一次翻转位置不同的最终数组摆到一起,剔除相同位置的相同数值,剩下的一定是2*t个位置,且其中t个位置升序,t个位置逆序,这样两数组最终贡献上的差值就抵消了,所以最终答案就两种情况,一种是不进行翻转操作,一种是最后一次才进行翻转。

具体代码如下:

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int mod = 1e9+7;
int a[100005], b[100005], p2[100005], n, m;

int f(int len, int type){//len段时的贡献,1代表全1,2代表全2 
	int res = 0;
	if(type == 1)
		for(int i = 1; i <= n; i++)
			res = ((res+a[i]*((((1+len)*len/2)%mod)%mod*n%mod-len*(i-1)%mod)%mod)+mod)%mod;
	else
		for(int i = 1; i <= n; i++)
			res = ((res+b[i]*((((1+len)*len/2)%mod)%mod*n%mod-len*(i-1)%mod)%mod)+mod)%mod;
	
	return res;
}

signed main(){
	scanf("%lld%lld", &n, &m);
	p2[0] = 1;
	for(int i = 1; i <= m; i++)
		p2[i] = p2[i-1]*2%mod;
	for(int i = 1; i <= n; i++)
		scanf("%lld", &a[i]);
	reverse(a+1, a+n+1);
	memcpy(b, a, sizeof a);
	reverse(a+1, a+n+1);
	int ans1 = f(p2[m], 1);
	int ans2 = ((f(p2[m], 2)-f(p2[m-1], 2)+f(p2[m-1], 1))%mod+mod)%mod; 
	printf("%lld\n", max(ans1, ans2));
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值