【GDOI2016模拟3.16】装饰

Description:

这里写图片描述

题解:

很容易想到如果不计一开始一列的相对顺序。

就可以重写每一列状态为0、1、2表示没有R,G,B的。

接着枚举第一列是哪个,再枚举有几个空,接着枚举奇数的空的个数,接着列方程求出奇数中有几个是谁开头的,然后组合数一波流。

Code:

#include<cstdio>
#include<algorithm>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;

const int mo = 1e9 + 7;

int n, a[3];

const int N = 2e6;

ll ksm(ll x, ll y) {
    ll s = 1;
    for(; y; y /= 2, x = x * x % mo)
        if(y & 1) s = s * x % mo;
    return s;
}

ll fac[N + 1], nf[N + 1], ans;

ll C(ll n, ll m) {
    if(n < m || n < 0 || m < 0) return 0;
    return fac[n] * nf[n - m] % mo * nf[m] % mo;
}

int main() {
    fac[0] = 1; fo(i, 1, N) fac[i] = fac[i - 1] * i % mo;
    nf[N] = ksm(fac[N], mo - 2); fd(i, N - 1, 0) nf[i] = nf[i + 1] * (i + 1) % mo;
    scanf("%d", &n);
    fo(i, 0, 2) scanf("%d", &a[i]), a[i] = n - a[i];
    fo(i, 0, 2) {
        fo(ii, 0, 1) {
            int g = a[i] - ii;
            if(g <= 0) continue;
            int y, z;
            if(i == 0) y = a[1], z = a[2];
            if(i == 1) y = a[0], z = a[2];
            if(i == 2) y = a[0], z = a[1];
            fo(e, 0, g) {
                if((y - z + g - e) & 1) continue;
                int oy = (y - z + g - e) / 2, oz = g - e - oy;
                int r = y - e - oy;
                ans = (ans + C(g + r - 1, r) * C(g, e) % mo * C(g - e, oy) % mo * ksm(2, e) % mo) % mo;
            }
        }
    }
    printf("%lld", ans * 2 % mo);
}

猜你喜欢

转载自blog.csdn.net/Cold_Chair/article/details/81084242