HDU2276——Kiki & Little Kiki 2

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2276

题目意思:给予一个01字符串,表示一串灯的明亮状态,现在每过一秒,如何这个灯的左边的灯是亮的,我们就改变他的明亮状态。(从左往右依次更新)注:第一个的左边是最后一个(即0的左边是n-1),问n秒后所有灯的明亮状态。

思路:采用矩阵快速幂啊!这个题十分有意思,采用了位运算,是真的没有想到。

1 0 0 0 0 0 1
1 1 0 0 0 0 0
0 1 1 0 0 0 0
0 0 1 1 0 0 0
0 0 0 1 1 0 0
0 0 0 0 1 1 0
0 0 0 0 0 1 1

以上是以样例一(0101111)为例的系数矩阵,我们发现对于相邻的两位只存在四种情况00,01,10,11,其中00,01保持原样不变,10和11分别变成11和10,我们惊奇的发现(1&1)^(1&1)=0,(1&1)^(1&0)=1,是不是满足这个变换?而(0&1)^(0&1)=0,(0&1)^(1&1)=1保持不变。这个就是这道题的难点,希望可以记住这个类型的变换。这样我们就可以通过上面的系数矩阵通过矩阵快速幂快速得到n秒后的状态了!!!

代码:

//Author: xiaowuga
#include <bits/stdc++.h>
#define maxx INT_MAX
#define minn INT_MIN
#define inf 0x3f3f3f3f
#define maxn 101 
using namespace std;
typedef long long ll;
int n;
struct Matrix{
    ll mat[maxn][maxn];
    Matrix operator * (const Matrix & m) const{
        Matrix tmp;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++){
                tmp.mat[i][j]=0;
                for(int k=0;k<n;k++){
                    tmp.mat[i][j]^=mat[i][k]&m.mat[k][j];
                }
            }
        return tmp;
    }
};
Matrix POW(Matrix &m,ll k){
    Matrix ans;
    memset(ans.mat,0,sizeof(ans.mat));
    for(int i=0;i<n;i++) ans.mat[i][i]=1;
    while(k){
        if(k&1) ans=ans*m;
        k/=2;
        m=m*m;
    }
    return ans;
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0);
    ll num;
    while(cin>>num){
        string q;
        cin>>q;
        n=q.size();
        Matrix m,f;
        memset(m.mat,0,sizeof(m.mat));
        memset(f.mat,0,sizeof(f.mat));
        for(int i=0;i<n;i++) f.mat[i][0]=q[i]-'0';
        m.mat[0][0]=m.mat[0][n-1]=1;
        for(int i=1;i<n;i++) m.mat[i][i-1]=m.mat[i][i]=1;
        Matrix x=POW(m,num);
        Matrix ans=x*f;
        for(int i=0;i<n;i++) cout<<ans.mat[i][0];
        cout<<endl;
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/xiaowuga/p/7351857.html