您的位置:首页 > 其它

矩阵练习3

2014-03-25 16:49 162 查看
POJ 3292 大湿给的TAG是佩尔方程,但是我直接用筛法变形给过了。。。
http://poj.org/problem?id=3292这道题我暑假集训的时候就过了。。。要去看代码和题意的去翻我前面的CSDN。。。
POJ 1320 http://poj.org/problem?id=1320 题意比较操蛋,我找DL翻译的- - 然后翻译了之后大致意思是给你这个人住的号码为a,街道尽头为b

然后要使得1+2+3+..a-1=a+1+a+2+...b相等,求出前十组满足条件的a和b的解。。首先很容易想到左边右边都是等差数列的和的形式,求和可以得到

2a^2=b^2+b然而根据大湿的TAG,我们知道佩尔方程是为了求解形如x^2-ty^2=1的二元二次不定方程的正整数解的一个方程,而且t不能是完全平方数。。然后

接下来的工作就是想办法凑出一个佩尔方程的形式了。。其实也蛮好凑得。。左右两边乘个4有 8a^2=4b^2+4b====>(2b+1)^2-8a^2=1 然后换元---->2b+1=x ,a=y,t=8

就转化为x^2-8y^2=1的形式。且显然第一组解为x=3 y=1,而经过递推可以得到xi+1=x1xi+ty1yi yi+1=x1yi+y1xi,是故又可以构造一个2*2的矩阵来求解了。。

在这里矩阵也好构造的很。。。

| x1 ty1 | | xi | | xi+1 |

| y1 x1 | *| yi |=| yi+1 | 然后剩下的就又有回到基本的求解过程了。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

struct juzhen{

long long  m[2][2];

};

juzhen mut(juzhen a,juzhen b)
{
   juzhen c;
   for(long long  i=0;i<2;i++)
   {
       for(long long  j=0;j<2;j++)
       {
           c.m[i][j]=0;
           for(long long  k=0;k<2;k++)
           {
               c.m[i][j]+=a.m[i][k]*b.m[k][j];
           }
       }
   }

    return c;
}

juzhen pow(juzhen a,long long  p)
{
    juzhen ans;
    ans.m[0][0]=ans.m[1][1]=1;
    ans.m[0][1]=ans.m[1][0]=0;
    while(p)
    {
        if(p%2==0)
        {
            a=mut(a,a);
            p/=2;
        }
        else
        {
            ans=mut(ans,a);
            p--;
        }

    }

    return ans;
}

int   main()
{

    juzhen ans;

    for(long long  i=1;i<=10;i++)
    {
        ans.m[0][0]=ans.m[1][1]=3;
        ans.m[0][1]=8;
        ans.m[1][0]=1;

        ans=pow(ans,i);
        int a=ans.m[1][0]*3+ans.m[1][1]*1;
        int b=(ans.m[0][0]*3+ans.m[0][1]*1-1)/2;

        printf("%10d%10d\n",a,b);
    }

    return 0;

}


HDU 4291
http://acm.hdu.edu.cn/showproblem.php?pid=4291
要求 g(g(g(n))) mod 109 + 7 已知g(n) = 3g(n - 1) + g(n - 2)g(1) = 1 g(0) = 0。

g(n)的矩阵构造已经是小菜一碟了,但是这里难处理的是三层迭代的过程,一开始很傻很天真以为可以把G(n)一层一层的给化掉,然后BALL用没有,然后这题就实在没办法动手,大湿给的TAG是暴力枚举循环节,大致猜到了那就还得求两个循环节是多少才行,但是又不会。。大湿只好告诉了我怎么暴力找循环节 从a=g(1),b=g(0)开始 求出后一个数,后一个数c对当前循环节取模得到一个新的数取代掉a,而a顺势取代掉b 直到重新有a=g(1),b=g(0)的时候证明该层循环节已经找到。。继续把这个数当做下一层用来取模的数找到内层的循环节,然后找到了题目就直接是求先对每一阶的G(n)快速幂中取了模,然后求出结果来了。。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

const long long  mod1=1000000007;
const long long mod2=222222224;
const long long mod3=183120;
long long n;

struct juzhen{

long long m[2][2];

};
juzhen mut(juzhen a,juzhen b,long long mod)
{
    juzhen c;
    /*memset(c.m,0,sizeof(c.m));
    for(int i=0;i<2;i++)
    {
        c.m[i][i]=1;
    }*/
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            c.m[i][j]=0;
            for(int k=0;k<2;k++)
            {
                c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
                c.m[i][j]%=mod;
            }
        }
    }
    return c;
}

long long  pow(juzhen a,long long p,long long mod)
{
    juzhen ans;
    ans.m[0][0]=ans.m[1][1]=1;
    ans.m[0][1]=ans.m[1][0]=0;
    while(p)
    {
        if(p%2==0)
        {
            a=mut(a,a,mod);
            p/=2;
        }
        else
        {
            ans=mut(a,ans,mod);
            p--;
        }
    }
    return ans.m[0][1];
}
int  main()
{
   while(scanf("%I64d",&n)!=EOF)
   {
       if(n==0)
        {
        printf("0\n");
        }
      else  if(n==1)
        {
            printf("1\n");
        }
        else
        {
            juzhen ans1;

            ans1.m[0][0]=3;
            ans1.m[0][1]=ans1.m[1][0]=1;
            ans1.m[1][1]=0;
            long long tmp1=pow(ans1,n,mod1);
            long long tmp2=pow(ans1,tmp1,mod2);
            long long tmp3=pow(ans1,tmp2,mod3);
            printf("%I64d\n",tmp3%mod3);
        }
   }

    return 0;
}


再附上暴力枚举循环节的代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const long long  mod=1000000007;
int main()
{
    long long  i,a,b,c;
    a=1,b=0;
    for(i=1;;i++)
    {
        c=(3*a+b)%mod;
        b=a;
        a=c;
        if(a==1&&b==0)
        {
            cout<<i<<endl;
            break;
        }
    }
    return 0;
}最内层的循环节在这里求出I之后把MOD


HDU 3483
http://acm.hdu.edu.cn/showproblem.php?pid=3483
构造矩阵十分巧妙。



就是求那货。。。

已知N x M

又是求和的式子,前面已经做到过好几次了,所以这一次不出意外肯定是把sn放到最后然后通过一个矩阵变成sn+1的形式了

然后再写一写有:sn+1=sn+(n+1)^x*x^n+1

首先再次感谢大湿原来给我出过一道

n

Σi^50 的题目,这道题目教会我再求i^k--->(i+1)^k的过程中,我们可以讲(i+1)^k二项展开来构造矩阵

i=0

所以这道题一开始的思路也是这样,把(n+1)^x顺势二项展开得到了一个式子,但是在x^n+1那里又被卡住了2天,最后大湿提醒我说x是已知的,可以提个x出来放进二项展开的

式子中去,终于恍然大悟,遂构造了(x+2)*(x+2)阶的矩阵进行求解,然后过了。。



#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

long long n,x,mod;

struct juzhen{

long long m[55][55];

};

juzhen mut(juzhen a,juzhen b)
{
    juzhen c;
    for(long long i=0;i<x+2;i++)
    {
        for(long long j=0;j<x+2;j++)
        {
            c.m[i][j]=0;
            for(long long k=0;k<x+2;k++)
            {
                c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
                c.m[i][j]%=mod;
            }
        }
    }
    return c;
}

juzhen pow(juzhen a,long long p)
{
    juzhen ans;
    memset(ans.m,0,sizeof(ans.m));
    for(long long i=0;i<x+2;i++)
    {
        ans.m[i][i]=1;
    }
    while(p)
    {
        if(p%2==0)
        {
            a=mut(a,a);
            p/=2;
        }
        else
        {
            ans=mut(ans,a);
            p--;
        }
    }
    return ans;
}

int main()
{

    while(cin>>n>>x>>mod)
    {
        if(n==-1&&x==-1&&mod==-1)
            return 0;

        juzhen ans;
        memset(ans.m,0,sizeof(ans.m));
        for(long long i=0;i<x+1;i++)
        {
            ans.m[i][0]=ans.m[i][i]=x;
        }
        for(long long i=2;i<x+1;i++)
        {
            for (long long j=1;j<i;j++)
            {
                ans.m[i][j] =(ans.m[i-1][j-1] + ans.m[i-1][j])%mod;
            }
        }
        for(int i=0;i<x+1;i++)
        {
            ans.m[x+1][i]=ans.m[x][i];
        }
        ans.m[x+1][x+1]=1;
        /*  for(long long i=0;i<x+1;i++)
        {
            for(long long j=0;j<x+1;j++)
            {
                cout<<ans.m[i][j]<<" ";
            }
            cout<<endl;
        }*/
        ans=pow(ans,n-1);
        long long sum=0;
        for(int i=0;i<x+2;i++)
        {
            sum+=(ans.m[x+1][i]*x)%mod;
            sum%=mod;
        }
        cout<<sum<<endl;
    }
    return 0;
}


矩阵专题到此暂时告一段落了。。。刷了这些题,不知道有没有什么很大的用处,可能也就是把自己的大脑适当的开发了一下吧。。但是开发了一下总比让大脑生锈强,即使再笨,笨鸟也能先飞,只要努力,也许就可以跟那些动脑多的,厉害的人的差距变小一点点了吧。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: