[报告]ZJU 3651 Cipher Lock

Abstract

ZJU 3651 Cipher Lock

组合计数 DP 矩阵乘法

 

Body

Source

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3651

Description

N个点围成一个环,每个点有两个属性(u, v),取值范围分别是[1, p]和[1, q]。已知其中8个点的属性,问有多少个环,满足相邻两点至少有一个属性值相同。

Solution

很明显的用矩阵加速的dp统计题。

一开始想错状态,把起点的情况也考虑进去,弄了个3x3({us,ut,其他}x{vs,vt,其他})=9维的矩阵,然后还要考虑vs,vt相等或者us,ut相等之类的情况,写了一下午,一脸血。

后来观察了下,发现合并后,其实跟起点的情况没有关系。

首先把点按照坐标排序,算相邻点之间的方案数,最后乘起来即可。

对于相邻的点,记f(n,{0,1},{0,1})表示从起点开始走n个点,u和终点的u是否相等,v和终点的v是否相等的方案数。转移比较容易。由于n很大所以要用矩阵乘法加速。

注意有点坐标相同的情况,特殊判断一下。

Code

#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

using namespace std;



typedef long long ll;



const ll mod = 1234567890ll;



struct sm {

    ll m[4][4];

    void init() {memset(m, 0, sizeof m);}

    sm() {init();}

    void eye() {for (int i = 0; i < 4; ++i) m[i][i] = 1;}

};



sm operator*(const sm &a, const sm &b) {

    sm res;

    for (int i = 0; i < 4; ++i)

        for (int j = 0; j < 4; ++j)

            for (int k = 0; k < 4; ++k)

                if (a.m[i][k] && b.m[k][j])

                    res.m[i][j] = (res.m[i][j]+a.m[i][k]*b.m[k][j])%mod;

    return res;

}



sm operator^(sm x, ll p) {

    sm res;

    res.eye();

    for (; p; p>>=1) {

        if (p&1) res = res*x;

        x = x*x;

    }

    return res;

}



struct snode {

    ll x, u, v;

    void read() {cin>>x>>u>>v; x--; u--; v--;}

    bool operator<(const snode &rhs) const {

        return x < rhs.x;

    }

}node[10];



ll N, p, q;



ll solve() {

    int i, j, k;

    ll res = 1;

    sort(node, node+8);

    node[8] = node[0];

    node[8].x += N;

    sm m;

    m.m[0][0]=m.m[0][1]=m.m[0][2]=m.m[1][3]=m.m[2][3] = 1;

    m.m[1][0]=m.m[1][1]=m.m[3][2] = (q-1)%mod;

    m.m[2][0]=m.m[2][2]=m.m[3][1] = (p-1)%mod;

    m.m[3][3] = p>1&&q>1?(p+q-3)%mod:0;

    //from i to i+1

    for (i = 0; i < 8; ++i) {

        if (node[i].x==node[i+1].x) {

            if (node[i].u^node[i+1].u || node[i].v^node[i+1].v) return 0;

            else continue;

        }

        sm now = m^(node[i+1].x-node[i].x);

        j = ((node[i].u!=node[i+1].u)<<1)|(node[i].v!=node[i+1].v);

        res = (res*now.m[0][j])%mod;

    }

    res %= mod;

    if (res<0) res += mod;

    return res;

}



int main() {

    int i, j, k;

    while (cin>>N>>p>>q) {

        for (i = 0; i < 8; ++i)

            node[i].read();

        cout<<solve()<<endl;

    }

    return 0;

}

你可能感兴趣的:(Lock)