hdu-2276(Kiki & Little Kiki 2)

矩陣快速冪的練習題,需要將題目轉化一下才能用矩陣快速冪。

題目大意:有n個燈,分別編號 1 到 n,它們構成一個環,1 的左邊是 n,k 的左邊是 k-1。時間每過 1 s,如果燈 i 左邊的燈是亮的,則燈 i 切換狀態(1 表示亮,0 表示暗)。附鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=2276

大體思路:這裏的難點在於如何想到用快速冪,因爲題目所給的秒數很大,單純模擬的話肯定超時,因此可以用矩陣快速冪來解。不過,構造矩陣也需要一點時間,這也可以算作難點,然後是一個小技巧,就是矩陣相乘後每一位與 2 相餘,這一點想到了的話用矩陣快速冪的思路也就清晰了。構造矩陣需要想到燈 i 的狀態和燈 i 左邊的狀態有聯繫,接着構造一個n×n 方,對角線爲 1,代表燈 i 自身,對角線的上方就是燈 i 左邊的燈,也置爲1,由此,矩陣構造完畢。係數矩陣C如下圖所示

1 1





1 1





1 1





1 1





1 1





1 1
1




1

而開始的矩陣爲題目給的燈初始狀態T。則該題目就轉爲求 T*C^M。

以下爲ac代碼:

#include<iostream>
#include<cstring>
using namespace std;

const int maxn=105;
const int mod=2;   //這一點很巧妙,沒有餘數爲2,矩陣快速冪也就沒法應用在該題上
int n;

struct Matrix{
    long long mat[maxn][maxn];
};
Matrix unit;  //單位矩陣

Matrix mul(Matrix a,Matrix b){
    Matrix c;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++){
            c.mat[i][j]=0;
            for(int k=0;k<n;k++){
                c.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
                c.mat[i][j]%=mod;
            }
    }
    return c;
}
Matrix mat_pow(Matrix a,long long p){
    Matrix temp=unit;
    while(p){
        if(p%2)
            temp=mul(temp,a);
        a=mul(a,a);
        p/=2;
    }
    return temp;
}

int main(){
    long long M;
    char s[maxn];
    memset(unit.mat,0,sizeof(unit.mat));
    for(int i=0;i<maxn;i++)    //構造單位矩陣
        unit.mat[i][i]=1;

    while(cin>>M){
        cin>>s;
        n=strlen(s);
        Matrix T,C;
        for(int i=0;i<n;i++)
            T.mat[0][i]=s[i]-'0';  //初始矩陣T
        memset(C.mat,0,sizeof(C.mat));
        for(int i=1;i<n;i++)           //構造係數矩陣
            C.mat[i][i]=C.mat[i-1][i]=1;
        C.mat[0][0]=C.mat[n-1][0]=1;

        Matrix D=mat_pow(C,M);  //係數矩陣快速冪
        D=mul(T,D);             //求最後結果
        for(int i=0;i<n;i++)
            cout<<D.mat[0][i];
        cout<<endl;
    }
    return 0;
}


發佈了39 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章