【矩陣---求A的1到N次冪之和】


引例: Matrix Power Series

題目大意,給定矩陣A,求A^1+A^2+A^3+...A^N。

題解:已知X=a,可以通過以下矩陣求出ans=a^1+a^2+...a^N ans=矩陣^n后第一行之和-1=矩陣^(n+1)后右上格的和-1

同理:矩陣也可以,只需要把1改為單位矩陣元即可。

左圖a是常數,1就是1; 右圖A是矩陣,1是單位元矩陣(主對角線是1)。

          

 

代碼1:矩陣^N,第一行之和-1。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=70;
int N,K,Mod;
struct mat
{
    int mp[maxn][maxn],len;
    mat(int x){ len=x; memset(mp,0,sizeof(mp)); }
    mat friend operator *(mat a,mat b)
    {
        mat res(a.len);
        for(int k=1;k<=res.len;k++)
         for(int i=1;i<=res.len;i++)
          for(int j=1;j<=res.len;j++)
            res.mp[i][j]=(res.mp[i][j]+a.mp[i][k]*b.mp[k][j])%Mod;
        return res;
    }
    mat friend operator ^(mat a,int x)
    {
        mat res(a.len);
        for(int i=1;i<=res.len;i++) res.mp[i][i]=1;
        while(x){
            if(x&1)res=res*a;  a=a*a;  x>>=1;
        }   return res;
    }
};
int main()
{
    scanf("%d%d%d",&N,&K,&Mod);
    mat array(N+N);
    for(int i=1;i<=N;i++)
      for(int j=1;j<=N;j++){ 
         scanf("%d",&array.mp[i][j]);
    } 
    for(int i=1;i<=N;i++) array.mp[i][i+N]=array.mp[i+N][i+N]=1;
    array=array^(K);
    for(int i=1;i<=N;i++) array.mp[i][i+N]-=1;
    for(int i=1;i<=N;i++){
        for(int j=1;j<N;j++)
           printf("%d ",(array.mp[i][j]+array.mp[i][j+N]+Mod)%Mod);
        printf("%d\n",(array.mp[i][N]+array.mp[i][N+N]+Mod)%Mod);
    }
    return 0;
}
View Code

代碼2:矩陣^N+1,右上格之和-1。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=70;
int N,K,Mod;
struct mat
{
    int mp[maxn][maxn],len;
    mat(int x){ len=x; memset(mp,0,sizeof(mp)); }
    mat friend operator *(mat a,mat b)
    {
        mat res(a.len);
        for(int k=1;k<=res.len;k++)
         for(int i=1;i<=res.len;i++)
          for(int j=1;j<=res.len;j++)
            res.mp[i][j]=(res.mp[i][j]+a.mp[i][k]*b.mp[k][j])%Mod;
        return res;
    }
    mat friend operator ^(mat a,int x)
    {
        mat res(a.len);
        for(int i=1;i<=res.len;i++) res.mp[i][i]=1;
        while(x){
            if(x&1)res=res*a;  a=a*a;  x>>=1;
        }   return res;
    }
};
int main()
{
    scanf("%d%d%d",&N,&K,&Mod);
    mat array(N+N);
    for(int i=1;i<=N;i++)
      for(int j=1;j<=N;j++){ 
         scanf("%d",&array.mp[i][j]);
    } 
    for(int i=1;i<=N;i++) array.mp[i][i+N]=array.mp[i+N][i+N]=1;
    array=array^(K+1);
    for(int i=1;i<=N;i++) array.mp[i][i+N]-=1;
    for(int i=1;i<=N;i++){
        for(int j=1;j<N;j++)
           printf("%d ",(array.mp[i][j+N]+Mod)%Mod);
        printf("%d\n",(array.mp[i][N+N]+Mod)%Mod);
    }
    return 0;
}
View Code

代碼3:利用二分。

 

--------------------分界線---------------------------

 

例題:HDU2243:考研路茫茫——單詞情結

題意:問長度位1到L的所有單詞中,有多少個不含給出的幾個單詞。

思路:利用矩陣得到可以26的1到N次冪。然后利用AC自動機得到基本矩陣X,再利用矩陣得到得到X^0+X^1+X^2...X^N。
比如得到26的0到N次冪和,就有矩陣a[
0][0]=26,a[0][1]=1,a[1][0]=0,a[1][1]=1;
矩陣^N后,第一行的和就是答案。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ull unsigned long long
const int maxn=40;
int ch[maxn][26],cnt;
int q[maxn],head,tail,Next[maxn],tag[maxn];
char s[20];
struct mat
{
    ull mp[maxn][maxn];
    mat(){memset(mp,0,sizeof(mp));}
    mat init(){ memset(mp,0,sizeof(mp));}
    mat friend operator *(mat a,mat b)
    {
        mat res;
        for(int k=0;k<=max(cnt,2);k++)
          for(int i=0;i<=max(cnt,2);i++)
            for(int j=0;j<=max(cnt,2);j++)
             res.mp[i][j]+=a.mp[i][k]*b.mp[k][j];
        return res;
    }
    mat friend operator ^(mat a,int x)
    {
        mat res; 
        for(int i=0;i<=cnt;i++) 
            res.mp[i][i]=1;
        while(x){
            if(x&1) res=res*a; 
            a=a*a; x>>=1;
        }   return res;
    }
};

mat array;

struct ACautom
{
    void update()
    {
        cnt=head=tail=0;
        memset(Next,0,sizeof(Next));
        memset(tag,0,sizeof(tag));
        memset(ch,0,sizeof(ch));
        array.init();
    }
    void insert()
    {
        int Now=0;
        for(int i=0;s[i];i++){
            int x=s[i]-'a';
            if(!ch[Now][x]) ch[Now][x]=++cnt;
            Now=ch[Now][x];
        } tag[Now]=1;
    }
    void build()
    {
        for(int i=0;i<26;i++){
            if(ch[0][i]) q[++head]=ch[0][i];    
            if(!tag[ch[0][i]]) array.mp[0][ch[0][i]]++;
        }
        while(tail<head){
            int u=q[++tail];
            for(int i=0;i<26;i++){
                if(ch[u][i]){
                    q[++head]=ch[u][i];
                    Next[ch[u][i]]=ch[Next[u]][i];
                    if(tag[Next[ch[u][i]]]) tag[ch[u][i]]=1;
                }
                else ch[u][i]=ch[Next[u]][i];
                if(!tag[ch[u][i]]) array.mp[u][ch[u][i]]++;
            }
        }
        cnt++;
        for(int i=0;i<=cnt;i++) array.mp[i][cnt]=1;
    }
    void qpow(int K)
    {
        ull ans,res=0;
        mat base;
        base.mp[0][0]=26; base.mp[0][1]=1;
        base.mp[1][0]=0;  base.mp[1][1]=1;
        base=base^K;
        ans=base.mp[0][0]+base.mp[0][1];
        array=array^K;
        for(int i=0;i<=cnt;i++) res=res+array.mp[0][i];
        cout<<ans-res<<endl;
    }
}Trie;
int main()
{
    int N,K;
    while(~scanf("%d%d",&N,&K)){
        Trie.update();
        for(int i=1;i<=N;i++) {
            scanf("%s",s);
            Trie.insert();
        }
        Trie.build();
        Trie.qpow(K);
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM