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
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}