prow2012-A3-0010

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

题意是说,一个类似拨水管游戏的格子图,每一格有L形水管,一形水管,或者空,然后求从最左流到最右有几种方案,题目有一个重要限制:水不能往左流。 

首先能闻出这题是用矩阵乘法做DP,DP定义f[i][j]表示第i列的第j格冒出个插头的方案数有多少种,

那么,当某格为1时,它只能从f[i-1][j]转移;当某格为2时,它可以从上方和下方最近的一个2处转移。



{{{


#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <set>
#include <map>
#include <sstream>
#include <string>
#include <math.h>
using namespace std;
#include <stdio.h>
#include <string.h>

struct Mat {
    long long M[6][6];

    void clear() {
        memset(M, 0, sizeof (M));
    }
};
int N, M, K;

void copy(Mat &A, Mat &B) {
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            A.M[i][j] = B.M[i][j];
}

void Mmut(Mat &A, Mat &B) {
    Mat C;
    int i, j, k;
    C.clear();
    for (i = 0; i < N; i++)
        for (j = 0; j < N; j++)
            if (A.M[i][j]) {
                for (k = 0; k < N; k++)
                {
                    C.M[i][k] += A.M[i][j] * B.M[j][k];
                    C.M[i][k]%=11142457;
                }
            }
    copy(A, C);
}
int main(){
    int i,j,a[100],k,P;
    while(scanf("%d%d",&M,&N)!=EOF){
        scanf("%d",&K);
        Mat init;
        init.clear();
        for (i=0;i<N;i++)
        init.M[0][i] = 1;
        for (i=0;i<K;i++){
            scanf("%d",&P);
            for (j=0;j<N;j++)
                scanf("%d",&a[j]);
            Mat round;
            round.clear();
            for (j=0;j<N;j++)
                if (a[j]==1)
                    round.M[j][j] = 1;
                else {
                    for (k=j-1;k>=0;k--)
                        if (a[k]==2) break;
                    if (k>=0) round.M[k][j] = 1;
                    for (k=j+1;k<N;k++)
                        if (a[k]==2) break;
                    if (k<N) round.M[k][j] = 1;
                }
            Mat res;
            res.clear();
            for (j=0;j<N;j++) res.M[j][j] = 1;
            while(P){
                if (P&1) Mmut(res,round);
                Mmut(round,round);
                P>>=1;
            }
            Mmut(init,res);
        }
        int res = 0;
        for (i=0;i<N;i++)
            res+=init.M[0][i],res%=11142457;
        printf("%d\n",res);
    }
}


}}}

题意是说,一个类似拨水管游戏的格子图,每一格有L形水管,一形水管,或者空,然后求从最左流到最右有几种方案,题目有一个重要限制:水不能往左流。

首先能闻出这题是用矩阵乘法做DP,DP定义f[i][j]表示第i列的第j格冒出个插头的方案数有多少种,

那么,当某格为1时,它只能从f[i-1][j]转移;当某格为2时,它可以从上方和下方最近的一个2处转移。

#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <set>
#include <map>
#include <sstream>
#include <string>
#include <math.h>
using namespace std;
#include <stdio.h>
#include <string.h>
struct Mat {
    long long M[6][6];
    void clear() {
        memset(M, 0, sizeof (M));
    }
};
int N, M, K;
void copy(Mat &A, Mat &B) {
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            A.M[i][j] = B.M[i][j];
}
void Mmut(Mat &A, Mat &B) {
    Mat C;
    int i, j, k;
    C.clear();
    for (i = 0; i < N; i++)
        for (j = 0; j < N; j++)
            if (A.M[i][j]) {
                for (k = 0; k < N; k++)
                {
                    C.M[i][k] += A.M[i][j] * B.M[j][k];
                    C.M[i][k]%=11142457;
                }
            }
    copy(A, C);
}
int main(){
    int i,j,a[100],k,P;
    while(scanf("%d%d",&M,&N)!=EOF){
        scanf("%d",&K);
        Mat init;
        init.clear();
        for (i=0;i<N;i++)
        init.M[0][i] = 1;
        for (i=0;i<K;i++){
            scanf("%d",&P);
            for (j=0;j<N;j++)
                scanf("%d",&a[j]);
            Mat round;
            round.clear();
            for (j=0;j<N;j++)
                if (a[j]==1)
                    round.M[j][j] = 1;
                else {
                    for (k=j-1;k>=0;k--)
                        if (a[k]==2) break;
                    if (k>=0) round.M[k][j] = 1;
                    for (k=j+1;k<N;k++)
                        if (a[k]==2) break;
                    if (k<N) round.M[k][j] = 1;
                }
            Mat res;
            res.clear();
            for (j=0;j<N;j++) res.M[j][j] = 1;
            while(P){
                if (P&1) Mmut(res,round);
                Mmut(round,round);
                P>>=1;
            }
            Mmut(init,res);
        }
        int res = 0;
        for (i=0;i<N;i++)
            res+=init.M[0][i],res%=11142457;
        printf("%d\n",res);
    }
}