您的位置:首页 > 其它

CodeForces 60 E.Mushroom Gnomes(矩阵快速幂)

2017-12-23 21:30 344 查看
Description

给出n个有序的整数ai,前x秒,每秒相邻两个数之间会多一个数,其值为这两个数的和,之后把所有数字排序,最后y秒依旧是两个数之间多一个这两个数的和,问最后得到的所有数字之和

Input

第一行输入四个整数n,x,y,p,之后输入不减的n个整数ai

(1≤n≤106,0≤x,y≤1018,x+y>0,2≤p≤109,0≤ai≤109)

Output

输出最后的得到的数字之和,结果模p之后输出

Sample Input

2 1 0 657276545

1 2

Sample Output

6

Solution

先不考虑排序,只需分析x秒后得到的数字之和中每个数被用了多少次即可

先考虑相邻的两个数,以a,b为例

第一秒后变成a,a+b,b,和为2a+2b

第二秒后变成a,2a+b,a+b,a+2b,b,和为5a+5b

第三秒后变成a,3a+b,2a+b,3a+2b,a+b,2a+3b,a+2b,a+3b,b,和为14a+14b

可以看出第x秒后和为1+∑i=0x−13i=3x+12

现在考虑整个序列,由于最小值和最大值只和一个数相邻,故其x秒后出现了3x+12次,但是其他值两边都会被用,故出现了2⋅3x+12−1=3x次,用矩阵快速幂可以求出3x+12和3x

再考虑排序,由于后y秒和前x秒过程一样,只要求出x秒后序列的最值与和即可,x秒后序列最小值显然是a1,下面求最大值

显然最大值是通过原先的最大值mx和次大值smx生成的,依旧是上面的例子,可以看出mx在x秒后最大值中出现f(x)次,smx在x秒后最大值中出现f(x−1)次,其中f(1)=1,f(2)=2,f(n)=f(n−1)+f(n−2)为斐波那契数列,依旧可以用矩阵快速幂求出

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef ll M[2][2];
int n,p;
ll x,y;
void Mul(M &A,M B)
{
M C;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
{
C[i][j]=0;
for(int k=0;k<2;k++)C[i][j]+=A[i][k]*B[k][j];
}
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
A[i][j]=C[i][j]%p;
}
void Pow(M &A,ll k)
{
M B;
B[0][0]=B[1][1]=1;
B[0][1]=B[1][0]=0;
while(k)
{
if(k&1)Mul(B,A);
Mul(A,A);
k>>=1;
}
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
A[i][j]=B[i][j];
}
int main()
{
while(~scanf("%d%I64d%I64d%d",&n,&x,&y,&p))
{
int mn,mx,smx,sum=0;
for(int i=1;i<=n;i++)
{
int temp;
scanf("%d",&temp);
temp%=p;
sum+=temp;
if(sum>=p)sum-=p;
if(i==1)mn=temp;
if(i==n-1)smx=temp;
if(i==n)mx=temp;
}
if(n==1)printf("%d\n",mn);
else
{
if(x==0)swap(x,y);
M A;
A[0][0]=A[0][1]=1,A[1][0]=0,A[1][1]=3%p;
Pow(A,x-1);
int a=(A[0][0]+A[0][1]*3%p+1)%p,b=A[1][1]*3%p;
sum=((ll)a*(mn+mx)%p+(ll)((sum-mn-mx)%p+p)%p*b%p)%p;
A[0][0]=A[0][1]=A[1][0]=1,A[1][1]=0;
Pow(A,x);
a=A[0][0],b=A[1][0];
mx=((ll)a*mx%p+(ll)b*smx%p)%p;
if(y==0)a=1,b=1;
else
{
A[0][0]=A[0][1]=1,A[1][0]=0,A[1][1]=3%p;
Pow(A,y-1);
a=(A[0][0]+A[0][1]*3%p+1)%p,b=A[1][1]*3%p;
}
sum=((ll)a*(mn+mx)%p+(ll)((sum-mn-mx)%p+p)%p*b%p)%p;
printf("%d\n",sum);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: