POJ 1320 Street Numbers Pell方程

http://poj.org/problem?id=1320

题意很简单,有序列 1,2,3...(a-1),a,(a+1)...b  要使以a为分界的 前缀和 和 后缀和 相等 求a,b

因为序列很特殊所以我们用数学方法就可以解决 : 

求和:  a*(a-1)/2 = (a+1+b)(b-a)/2

化简: 2a2  = b+ b

两边乘4,构造完全平方项 (2b+1)2 - 8a2  = 1 

令 x = 2*b+1; 

    y = a;

我们就得到了一个形如Pell方程x- Dy2  = 1  的式子 x- 8y2  = 1 

这题就是求Pell方程的第K个解 , 因为方程已经告诉你了

所以我们可以目测出最小解以用来构造矩阵来求出后面的解

下面就是构造系数矩阵的方法: 


 已知Pell方程为 x- Dy2  = 1

为了得到第k个解,我们需要构造系数矩阵

为了得到系数矩阵,我们必须知道该方程的最小特解 x0,y0

于是我们就能得到系数矩阵:

 

xk y就是Pell方程的第k个解

 


 对于Pell方程最小特解的求法,可以参照我上一篇 http://www.cnblogs.com/Felix-F/p/3222741.html

当然这题一眼就能看出最小特解为x=3,y=1

用矩阵快速幂小加了一下速                   (应该是逗比了..这样反而复杂度高了....直接记录各层次的矩阵就行...


struct matrix
{
    LL ma[2][2];
};
int n = 2;
matrix operator * (matrix a,matrix b)
{
    matrix temp;
    memset(temp.ma,0,sizeof(temp.ma));
    for(int i = 0; i < n ; i++)
        for(int j = 0; j < n ; j++)
            for(int k = 0 ; k < n ; k++)
                temp.ma[i][j] = temp.ma[i][j] + (a.ma[k][i] * b.ma[j][n-k-1]);
    return temp;
}
matrix operator + (matrix a,matrix b)
{
    for(int i = 0; i < n ; i++)
        for(int j = 0; j < n ; j++)
            a.ma[i][j] = (a.ma[i][j] + b.ma[i][j]) ;
    return a;
}
matrix m_pow(matrix a,int n)
{
    if(n == 1) return a;
    matrix temp = m_pow(a,n/2);
    if(n & 1) return temp * temp * a;
    else return temp * temp ;
}
int main()
{
    matrix a;
    a.ma[0][0] = 1;
    a.ma[0][1] = 3;
    a.ma[1][0] = 3;
    a.ma[1][1] = 8;
    for(int i = 1 ;i <= 10 ; i++)
    {
        matrix tmp = m_pow(a,i);
        LL s1 = tmp.ma[0][1] * 3 + tmp.ma[1][1] * 1;
        LL b = (s1-1)/2;
        LL s2 = tmp.ma[0][0] * 3 + tmp.ma[1][0] * 1;
        LL a = s2;
        printf("%10.lld%10.lld
",a,b);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Felix-F/p/3223323.html