1. 程式人生 > >Tr A - 杭電1575(矩陣快速冪模板)

Tr A - 杭電1575(矩陣快速冪模板)

題目連結: Tr A-杭電1575

Problem Description

A 為一個方陣,則 Tr A 表示 的跡(就是主對角線上各項的和),現要求Tr(A^k)%9973
 

Input

資料的第一行是一個 T,表示有 T 組資料。
每組資料的第一行有 n(2 <= n <= 10) k(2 <= k < 10^9) 兩個資料。接下來有 n 行,每行有 個數據,每個資料的範圍是  [0,9],表示方陣 A 的內容。
 

Output

對應每組資料,輸出 Tr(A^k)%9973


 

Sample Input

2
2 2
1 0
0 1
3 99999999
1 2 3
4 5 6
7 8 9

 

Sample Output

2
2686

題意描述:

 

給你一個 n(1<n<11)階方陣,讓你計算出它的 k 次方(不用輸出),並且最後輸出它主對角線的所有元素之和。中間還有一個取模運算,意思是每次計算的值都要對 9973 進行取模,使它處於 0~9972 

 

思想解析:

 

題目樣例中給了 99999999 次方,所以肯定不能直接去算,直接算肯定超時的,所以這就涉及到了快速冪的思想,可以這麼解釋:每個十進位制數都可以變換成二進位制,比如21

,換成二進位制是10101,也就是 21 = 1+4+16 ,而計算機儲存數字的方法就是變換成二進位制,所以這個數的二進位制位為 1 的時候,就乘,不是 1,就自乘。所以可以用右移的方法,來控制乘不乘

有關快速冪思想的,可以參考整數快速冪這個部落格,這裡面講的比較詳細。

 

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
struct Ride      ///用結構體來存放矩陣比較方便
{
    int e[20][20];
};
int n;

Ride ride(Ride a,Ride b) ///兩個矩陣相乘
{
    Ride c;
    memset(c.e,0,sizeof(c.e));
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            for(int k=1; k<=n; k++)
                c.e[i][j] = (c.e[i][j] + a.e[i][k] * b.e[k][j]) % 9973;
    return c;
}
int main()
{
    Ride rec,ans;
    int t,k,sum;
    cin >> t;
    while(t--)
    {
        sum=0;
        scanf("%d %d",&n,&k);
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                scanf("%d",&rec.e[i][j]);

        memset(ans.e,0,sizeof(ans.e));///將ans矩陣變成單位矩陣
        for(int i=1; i<=n; i++)
            ans.e[i][i]=1;

        while(k)
        {
            if(k & 1) ///當k的最後一位是1時,ans*rec
                ans=ride(ans,rec);
            rec=ride(rec,rec);///每次迴圈 rec都要自乘
            k >>= 1; ///k右移,相當於k/2
        }

//        for(int i=1; i<=n; i++)    ///輸出矩陣
//        {
//            for(int j=1; j<=n; j++)
//                printf("%d ",ans.e[i][j]);
//            cout << endl;
//        }

        for(int i=1; i<=n; i++) ///計算對角線和
            sum = (sum+ans.e[i][i]) % 9973;
        cout << sum % 9973 << endl;
    }
    return 0;
}