【矩阵专题】

http://acm.hdu.edu.cn/webcontest/contest_show.php?cid=6930


1000:

题意:裸的斐波拉契,裸的不能再裸 n<10^12;


代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#define oo 0x13131313
#define LL long long
using namespace std;
struct node
{
    int mat[2][2];
};
node a={1,1,1,0};
node ret={1,0,0,1};
node NUL={0,0,0,0};
node matmult(node A,node B,int mod)
{
    node C=NUL;
    for(int i=0;i<2;i++)
         for(int j=0;j<2;j++)
           for(int k=0;k<2;k++)
    {
        C.mat[i][j]=(C.mat[i][j]+A.mat[i][k]*B.mat[k][j])%mod;
    }
    return C;
}
node quickmatpow(node A,LL n,int mod)
{
    node c=ret;
    while(n!=0)
    {
        if(n&1==1) c=matmult(c,A,mod);
        n=n>>1;
        A=matmult(A,A,mod);
    }
    return c;
}
LL n;
void init()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
}
int main()
{
 //   init();
    node c;
	while(cin>>n&&n!=-1)
    {
        c=quickmatpow(a,n,10000);
        printf("%d\n",c.mat[0][1]);
    }
}



1001

题意

A为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973。
裸的 没什么好说的
/*
第一次没过样例是因为 写ret 的时候 只给对角线赋值为1 忘记clear了
*/
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#define oo 0x13131313
#define LL long long
using namespace std;
void init()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
}
struct node
{
    int mat[15][15];
    void clear()
    {
        for(int i=0;i<15;i++)
             for(int j=0;j<15;j++)
             mat[i][j]=0;
    }
    void ret()
    {
          for(int i=0;i<15;i++)
             for(int j=0;j<15;j++)
             mat[i][j]=0;
        for(int i=0;i<15;i++)
            mat[i][i]=1;
    }
};
node fir;
LL n,k;
node matmult(node a,node b,int mod)
{
    node c;
    c.clear();
    for(int i=0;i<n;i++)
      for(int j=0;j<n;j++)
         for(int k=0;k<n;k++)
           c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;
    return c;
}
node quickmatpow(node a,LL n,int mod)
{
    node c;
    c.ret();
    while(n!=0)
    {
        if(n&1==1)  c=matmult(c,a,mod);
        n=n>>1;
        a=matmult(a,a,mod);
    }
    return c;
}
void input()
{
    scanf("%I64d%I64d",&n,&k);
    for(int i=0;i<n;i++)
      for(int j=0;j<n;j++)
       scanf("%d",&fir.mat[i][j]);
}
void solve()
{
   node c;
   int ans=0;
   c=quickmatpow(fir,k,9973);
   for(int i=0;i<n;i++)
   {
       ans=(ans+c.mat[i][i])%9973;
   }
   printf("%d\n",ans);
}
int main()
{
   // init();
	int T;
	cin>>T;
	while(T--)
    {
        input();
        solve();
    }
    return 0;
}



1002

题意:

A是一个矩阵 计算S=A+A^2......A^k-1+A^k;


区分奇偶来二分! 看了题解才会做的

本来的想法是涉及到矩阵的逆的

/*
1.WA  不明原因 改成全long long

2.

2 1000000 4
0 1
1 1
99%错误答案:
0 0
0 0

调试原因:不清楚
3.WA 继续调试2
4.发现原因 n为奇数时处理错误
*/
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#define oo 0x13131313
#define LL long long
using namespace std;
struct node
{
    LL mat[40][40];
    void clear()
    {
        for(int i=0;i<40;i++)
            for(int j=0;j<40;j++)
            mat[i][j]=0;
    }
    void ret()
    {
        clear();
        for(int i=0;i<40;i++)
            mat[i][i]=1;
    }
};
LL n,k,m;
node A;
void init()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
}
void input()
{
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        scanf("%I64d",&A.mat[i][j]);
}
node matmult(node a,node b,LL mod)
{
    node c;
    c.clear();
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            for(int k=0;k<n;k++)
            c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;
    return c;
}
node quickmatpow(node a,LL n,LL mod)
{
    node c;
    c.ret();
    while(n!=0)
    {
        if(n&1==1) c=matmult(c,a,mod);
        n=n>>1;
        a=matmult(a,a,mod);
    }
    return c;
}
node matadd(node a,node b,LL mod)
{
  node c;
  for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    c.mat[i][j]=(a.mat[i][j]+b.mat[i][j])%mod;
    return c;
}
node getans(int n,int mod)
{
    node c,d;
    c.clear();
    d.clear();
    if(n==1) return A;
    else
    {
        c=getans(n/2,mod);
        if(n%2==0)
        {
            d=quickmatpow(A,n/2,mod);
            return matadd(c,matmult(d,c,mod),mod);
        }
        else
        {
            d=quickmatpow(A,(n/2)+1,mod);
            return matadd(d,matadd(c,matmult(d,c,mod),mod),mod);
        }
    }
}
void solve()
{
    node ans;
    ans.clear();
    ans=getans(k,m);
    for(int i=0;i<n;i++)
      {
       for(int j=0;j<n;j++)
        {
            printf("%I64d",ans.mat[i][j]);
            if(j!=n-1) printf(" ");
        }
        printf("\n");
      }
}
int main()
{
    //init();
    while(cin>>n>>k>>m)
    {
        input();
        solve();
    }
}


1003

题意:

询问长度为N的队伍中 可能为M,或F 问不存在 FFF或FMF的排列总数。

之前做过的一道题

http://blog.csdn.net/zy691357966/article/details/43084647

#include <cstdio>  
#include <cstdlib>  
#include <cmath>  
#include <cstring>  
#include <ctime>  
#include <algorithm>  
#include <iostream>
#include <sstream>
#include <string>
#define oo 0x13131313   
using namespace std;
int L,M;
struct node
{
    int mat[5][5];
}a,e,ans;
int mat2[5];
void CSH()
{
    mat2[1]=9;
    mat2[2]=6;
    mat2[3]=4;
    mat2[4]=2;
    for(int i=1;i<=4;i++)
{
        e.mat[i][i]=1;
        mat2[i]=mat2[i]%M;
}
    memset(a.mat,0,sizeof(a.mat));
    a.mat[1][1]=a.mat[1][3]=a.mat[1][4]=1;
    a.mat[2][1]=a.mat[3][2]=a.mat[4][3]=1;
}
node MatrixMult(node A,node B,int mod)
{
    node p;
    memset(p.mat,0,sizeof(p.mat));
    for(int i=1;i<=4;i++)
     for(int j=1;j<=4;j++)
     {
          for(int k=1;k<=4;k++)
         p.mat[i][j]+=A.mat[i][k]*B.mat[k][j];
         p.mat[i][j]=p.mat[i][j]%mod;
     }
     return p;
}
node kuaisumi(node A,int N,int mod)
{
    node di=e;
    while(N>0)
    {
        if(N&1)
        {
            di=MatrixMult(di,A,mod);
        }
        A=MatrixMult(A,A,mod);
        N=N>>1;
    }
    return di;
}
void solve()
{
    int ANS=0;
    for(int i=1;i<=4;i++)
    {
        ANS+=ans.mat[1][i]*mat2[i];
        ANS=ANS%M;
    }
    printf("%d\n",ANS);
}
int main()
{
    while(cin>>L>>M)
    {
        CSH();
        if(L>4)
        ans=kuaisumi(a,L-4,M);
        if(L>4)
        solve();
        else 
        printf("%d\n",mat2[L]);
    }
    return 0;
}


1004

题目大意:
If x < 10 f(x) = x.
If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);
And ai(0<=i<=9) can only be 0 or 1 .


齐次递推,很容易由1003 得出公式

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#define LL long long
#define oo 0x13131313
using namespace std;
LL k,m;
void init()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
}
struct node
{
    LL mat[15][15];
    void clear() {memset(mat,0,sizeof(mat));}
    void ret()   {
                    clear();
                    for(int i=0;i<15;i++)
                        mat[i][i]=1;
                 }
};
node A;
void input()
{
    A.clear();
    for(int i=0;i<10;i++)
    scanf("%d",&A.mat[0][i]);
    for(int i=1;i<10;i++)
    A.mat[i][i-1]=1;
}
node matmult(node a,node b,LL mod)
{
    node c;c.clear();
    for(int i=0;i<10;i++)
        for(int j=0;j<10;j++)
          for(int k=0;k<10;k++)
           c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;
    return c;
}
node quickmatpow(node a,LL n,LL mod)
{
    node c;c.ret();
    while(n!=0)
    {
        if(n&1==1) c=matmult(c,a,mod);
        n=n>>1;
        a=matmult(a,a,mod);
    }
    return c;
}
void solve()
{
    LL ans=0;
    node c;c.clear();
    c=quickmatpow(A,k-9,m);
    for(int i=0;i<10;i++)
    ans=(ans+c.mat[0][i]*(9-i))%m;
    printf("%I64d\n",ans);
}
int main()
{
   // init();
	while(cin>>k>>m)
    {
        input();
        solve();
    }
    return 0;
}


接下来几个题目太强悍了 我必须新写一篇

posted on 2015-04-03 18:38  DDUPzy  阅读(120)  评论(0编辑  收藏  举报

导航