码迷,mamicode.com
首页 > 其他好文 > 详细

【ZOJ】Nice Patterns Strike Back(矩阵快速乘法)

时间:2015-05-26 23:29:52      阅读:286      评论:0      收藏:0      [点我收藏+]

标签:

dp[[i][j] = sum(dp[i - 1][k]) (k -> j)

状态方程,因为N很大而M很小,所以第一时间可以想到矩阵优化

可能之前没做过类似的题被卡的很厉害。

另外用C++写大数真心麻烦。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 45;
const int maxd = 30005;
char n[maxd],n_two[maxd],s[maxd];
int  m,mod,cntx;
struct Matx{
    int n,m;
    int mat[maxn][maxn];
    Matx(){
        memset(mat,0,sizeof(mat));
    }
    friend Matx operator * (Matx p,Matx q){
        Matx temp;
        memset(temp.mat,0,sizeof(temp.mat));
        temp.n = p.n; temp.m = q.m;
        for(int i = 0; i < p.n; i++){
            for(int j = 0; j < q.m; j++){
                for(int k = 0; k < q.n; k++){
                    temp.mat[i][j] += p.mat[i][k] * q.mat[k][j];
                    temp.mat[i][j] %= mod;
                }
            }
        }
        return temp;
    }
};
Matx base,ans,start;
void cost(){
    int L = strlen(n);
    n[L - 1] --;
    for(int i = L - 1; i >= 0; i--){
        int e = n[i] - '0';
        if(e >= 0) break;
        else{
            n[i - 1] --;
            n[i] += 10;
        }
    }
    int t;
    for(t = 0; t < L && n[t] == '0'; t++);
    if(t == L) n[L++] = '0';
    n[L] = '\0';
    strcpy(s,n + t);
    strcpy(n,s);
}
void init(){
    int t = (1 << m);
    base.n = base.m = t;
    memset(ans.mat,0,sizeof(ans.mat));
    memset(start.mat,0,sizeof(start.mat));
    for(int i = 0; i < base.n; i++){
        for(int j = 0; j < base.m; j++){
            base.mat[i][j] = 1;
            for(int k = 0; k < m - 1; k++){
                int a1 = (1 << k) & i,a2 = (1 << k) & j;
                int b1 = (1 << (k + 1)) & i,b2 = (1 << (k + 1)) & j;
                if(!a1 && !b1 && !a2 && !b2){
                    base.mat[i][j] = 0;
                    break;
                }
                else if(a1 && b1 && a2 && b2){
                    base.mat[i][j] = 0;
                    break;
                }
            }
        }
    }
    ans.n = 1; ans.m = t;
    for(int i = 0; i < ans.m; i++)
        ans.mat[0][i] = 1;
    start.n = start.m = t;
    for(int i = 0; i < start.n; i++)
        start.mat[i][i] = 1;
}
bool can_div2(){
    int L = strlen(n);
    int v = 0;
    for(int i = 0; i < L; i++){
        v = v * 10 + n[i] - '0';
        v %= 2;
    }
    if(!v) return true;
    return false;
}
void solve_div2(){
    int L = strlen(n);
    int v = 0,cnt = 0;
    for(int i = 0; i < L; i++){
        v = v * 10 + n[i] - '0';
        int e = v / 2;
        s[cnt++] = e + '0';
        v %= 2;
    }
    int t;
    for(t = 0; t < cnt && s[t] == '0'; t++);
    if(cnt == t) s[cnt++] = '0';
    s[cnt] = '\0';
    strcpy(n,s + t);
}
void solve_to_two(){
    if(strcmp(n,"0") == 0) return;
    if(can_div2()) n_two[cntx++] = '0';
    else n_two[cntx++] = '1';
    solve_div2();
    solve_to_two();
}
Matx Pow(){
    int cc = 0;
    for(int i = 0; i < cntx; i++){
        if(n_two[i] == '1'){
            start = start * base;
            cc ++;
        }
        base = base * base;
    }
    ans = ans * start;
    int ret = 0;
    for(int i = 0; i < ans.m; i++){
        ret += ans.mat[0][i];
        ret %= mod;
    }
    printf("%d\n",ret);
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        cntx = 0;
        scanf("%s%d%d",n,&m,&mod);
        cost();
        init();
        solve_to_two();
        Pow();
        if(T)
            puts("");
    }
    return 0;
}

【ZOJ】Nice Patterns Strike Back(矩阵快速乘法)

标签:

原文地址:http://blog.csdn.net/u013451221/article/details/46038261

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!