team2012-F3-sol-0017

从 Trac 迁移的文章

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

原文章内容如下:

{{{
题意:
给定一个n边形,每个顶点有两个数u和v,且 1 <= u <= p, 1 <= v <= q,并且要满足相邻的两个点至少有一个数字相同
当其中8个点的数值给定以后,求总方案数
解法:
分8段来考虑,在每一段上,设f[i]为一个4维向量表示从起点到i的方案数,其中:
f[i][0]为两个数与结尾的两个数都不同的方案数,
f[i][1]为只有第一个与结尾相同的方案数,
f[i][2]为只有第二个与结尾相同的方案数,
f[i][3]为两个都与结尾相同的方案数。

              {p+q-3, p-1, q-1, 0  }
              {1,     q-1, 0,   q-1}
那么 f[i+1] = {1,     0,   p-1, p-1} × f[i],这样用矩阵乘法乘到结尾,然后结尾一定要取“两个都相同的”即可
              {0,     1,   1,   1  }

}}}
{{{
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;

const LL MOD = 1234567890;
LL n, p, q, ans;

struct ele
{
    LL x, p, q;
}a[10];

struct mat
{
    LL dt[4][4];
    mat()
    {
        memset(dt, 0, sizeof(dt));
        for(int i=0;i<4;i++)
            dt[i][i] = 1;
    }
    mat operator*(const mat& ano)
    {
        mat ret;
        memset(&ret, 0, sizeof(ret));
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                for(int k=0;k<4;k++)
                {
                    ret.dt[i][j] += (dt[i][k] * ano.dt[k][j]) % MOD;
                    ret.dt[i][j] %= MOD;
                }
        return ret;
    }
    void operator*=(mat& ano)
    {
        (*this) = ano * (*this);
    }
}m;

void init()
{
    LL tmp[4][4] = {
        {p+q-3, p-1, q-1, 0},
        {1,     q-1, 0,   q-1},
        {1,     0,   p-1, p-1},
        {0,     1,   1,   1}
    };
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            m.dt[i][j] = tmp[i][j] % MOD;
}

void gao(int k)
{
    mat tm = m, res;
    LL pow = a[k+1].x - a[k].x;
    while(pow)
    {
        if(pow & 1)
            res *= tm;
        tm *= tm;
        pow >>= 1;
    }

    if(a[k+1].p == a[k].p && a[k+1].q == a[k].q)
        ans *= res.dt[3][3];
    else if(a[k+1].q == a[k].q)
        ans *= res.dt[3][2];
    else if(a[k+1].p == a[k].p)
        ans *= res.dt[3][1];
    else
        ans *= res.dt[3][0];
    ans %= MOD;
}

bool cmp(ele a, ele b)
{
    return a.x < b.x;
}

int main()
{
    while(~scanf("%lld %lld %lld", &n, &p, &q))
    {
        init();
        for(int i=1;i<=8;i++)
            scanf("%lld %lld %lld", &a[i].x, &a[i].p, &a[i].q);
        sort(a+1, a+8+1, cmp);
        a[9] = a[1];
        a[9].x += n;

        ans = 1;
        for(int i=1;i<=8;i++)   gao(i);
        printf("%lld\n", ans);
    }
    return 0;
}
}}}
题意:
给定一个n边形,每个顶点有两个数u和v,且 1 <= u <= p, 1 <= v <= q,并且要满足相邻的两个点至少有一个数字相同
当其中8个点的数值给定以后,求总方案数
解法:
分8段来考虑,在每一段上,设f[i]为一个4维向量表示从起点到i的方案数,其中:
f[i][0]为两个数与结尾的两个数都不同的方案数,
f[i][1]为只有第一个与结尾相同的方案数,
f[i][2]为只有第二个与结尾相同的方案数,
f[i][3]为两个都与结尾相同的方案数。
              {p+q-3, p-1, q-1, 0  }
              {1,     q-1, 0,   q-1}
那么 f[i+1] = {1,     0,   p-1, p-1} × f[i],这样用矩阵乘法乘到结尾,然后结尾一定要取“两个都相同的”即可
              {0,     1,   1,   1  }
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const LL MOD = 1234567890;
LL n, p, q, ans;
struct ele
{
    LL x, p, q;
}a[10];
struct mat
{
    LL dt[4][4];
    mat()
    {
        memset(dt, 0, sizeof(dt));
        for(int i=0;i<4;i++)
            dt[i][i] = 1;
    }
    mat operator*(const mat& ano)
    {
        mat ret;
        memset(&ret, 0, sizeof(ret));
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                for(int k=0;k<4;k++)
                {
                    ret.dt[i][j] += (dt[i][k] * ano.dt[k][j]) % MOD;
                    ret.dt[i][j] %= MOD;
                }
        return ret;
    }
    void operator*=(mat& ano)
    {
        (*this) = ano * (*this);
    }
}m;
void init()
{
    LL tmp[4][4] = {
        {p+q-3, p-1, q-1, 0},
        {1,     q-1, 0,   q-1},
        {1,     0,   p-1, p-1},
        {0,     1,   1,   1}
    };
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            m.dt[i][j] = tmp[i][j] % MOD;
}
void gao(int k)
{
    mat tm = m, res;
    LL pow = a[k+1].x - a[k].x;
    while(pow)
    {
        if(pow & 1)
            res *= tm;
        tm *= tm;
        pow >>= 1;
    }
    if(a[k+1].p == a[k].p && a[k+1].q == a[k].q)
        ans *= res.dt[3][3];
    else if(a[k+1].q == a[k].q)
        ans *= res.dt[3][2];
    else if(a[k+1].p == a[k].p)
        ans *= res.dt[3][1];
    else
        ans *= res.dt[3][0];
    ans %= MOD;
}
bool cmp(ele a, ele b)
{
    return a.x < b.x;
}
int main()
{
    while(~scanf("%lld %lld %lld", &n, &p, &q))
    {
        init();
        for(int i=1;i<=8;i++)
            scanf("%lld %lld %lld", &a[i].x, &a[i].p, &a[i].q);
        sort(a+1, a+8+1, cmp);
        a[9] = a[1];
        a[9].x += n;
        ans = 1;
        for(int i=1;i<=8;i++)   gao(i);
        printf("%lld\n", ans);
    }
    return 0;
}