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

Description

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

Input

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

(1n106,0x,y1018,x+y>0,2p109,0ai109)

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=0x13i=3x+12

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

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

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

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

你可能感兴趣的:(Code,Forces,快速幂)