[BZOJ4487] [JSOI2015]染色问题

这个嘛…容斥原理推一推公式就好啦>..<

选定i行,j列,k种颜色
i行可有颜色,也可没有,没有选的不能有涂色
j列类似
k种颜色可出现也可不出现,没有选颜色的不能用
这个有 (k+1)ij 种方案

那么总答案就是

i=0Nj=0Mk=0CCiNCjMCkC(1)N+M+Cijk(k+1)ij

我们显然不能接受O(NMC)的复杂度,然而题中400的数据范围奥妙重重,让这个算法水过了>..<我非常不开心

那么我们来想想怎么优化吧

有一个非常显而易见的多项式展开的公式

(X+1)Y=i=0YCiYXi

我们倒着来

原式稍稍变一下形

i=0Nk=0C(CiNCkC(1)N+M+Cik  j=0MCjM(1)j((k+1)i)j)

右边那个sigma的右边是不是和多项式展开公式形似呢,嘿嘿嘿

i=0Nk=0C(CiNCkC(1)N+M+Cik(1(k+1)i)M)

于是时间就变成O(NClogM)啦>..<
O(NMC)水过的,是异端,要批斗

#include 
const int MOD = 1000000007;
long long CC[401][401], POW[402][401], OUT, BASE, LOW;
int N, M, C;
inline int inv(int x)
{
    return x & 1 ? MOD - 1 : 1;
}
long long POWER(long long a, int b)
{
    long long r = 1;
    for (; b; b >>= 1)
    {
        if (b & 1)
            r = r * a % MOD;
        a = a * a % MOD;
    }
    return r;
}
int main()
{
    scanf("%d%d%d", &N, &M, &C);
    for (int i = 0; i <= N || i <= C; i++)
    {
        CC[i][0] = 1;
        for (int j = 1; j <= i; j++)
        {
            CC[i][j] = CC[i - 1][j - 1] + CC[i - 1][j];
            if (CC[i][j] >= MOD)
                CC[i][j] -= MOD;
        }
    }
    for (int i = 1; i <= C + 1; i++)
    {
        POW[i][0] = 1;
        for (int j = 1; j <= N; j++)
            POW[i][j] = POW[i][j - 1] * i % MOD;
    }
    for (int i = 0; i <= C; i++)
        for (int j = 0; j <= N; j++)
        {
            BASE = CC[C][i] * CC[N][j] % MOD * inv(N ^ M ^ C ^ i ^ j) % MOD;
            LOW = (MOD - POW[i + 1][j]) + 1;
            if (LOW >= MOD)
                LOW -= MOD;
            OUT += BASE * POWER(LOW, M) % MOD;
            if (OUT >= MOD)
                OUT -= MOD;
        }
    printf("%lld\n", OUT);
    return 0;
}

你可能感兴趣的:(BZOJ)