【题目大意】

求n*n的棋盘,每行每列都有2个黑格子的方案数。

n<=10^7

【题解】

zzq的做法好神奇啊

行列建点,二分图

左边有i个点,右边有j个点的方案数 f[i,j]

左边有i个点,2个已经有1个度,右边有j个点的方案数 g[i,j]

g[i,j] = f[i-2,j-1]*j + g[j,i-2]*P(j,2)

f[i,j] = g[i,j-1] * C(i,2) = g[j,i-1] * C(j,2)

g[j,i-2] = g[i-1,j-1] * C(i-1,2) / C(j,2)

g[i,j] = g[i-2,j-2] * C(i-2,2) * j + g[i-1, j-1] * C(i-1,2) / C(j,2) * P(j,2)

g[i,j] = g[i-2,j-2] * C(i-2,2) * j + g[i-1, j-1] * C(i-1,2) * 2

g[x] = g[x, x-1] 

g[x] = g[x-2] * C(x-2, 2) * (x-1) + g[x-1] * C(x-1, 2) * 2

ans = sigma (C(x,2) * g[x])

Q: 为什么从f转移到g,只乘了右边选择的部分,不管左边;从g转移到f,只乘了左边的部分,不管右边?

A: g实际的意义是我钦定左边最后两个度数为1的方案数,f实际的意义是我钦定右边最后1或2个是我最后填进来。 我从g到f,目的是消去两个度为1的点,重点是消去,我要优先考虑消除哪两个点,按照我g的定义,每两个度数为1的点作为选择,都有这么多方案,所以要乘组合数;从f到g,目的是制造两个度为1的点,按照f的定义,每1或2个点作为选择,都有这么多方案,所以要乘j和后面的那个组合数。意义在于,我要有一个顺序来填数,不能xjb填,这样会统计重复方案,我们用钦(ying)点来避免这样的问题。

 「6月雅礼集训 2017 Day2」B

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

# define RG register
# define ST static

const int M = 1e7 + 10;
const int mod = 998244353;

int n, g[M], ans;

inline int C(int n, int k = 2) {
    return (ll)n * (n-1) / 2 % mod;
}

int main() {
//    freopen("B.in", "r", stdin);
//    freopen("B.out", "w", stdout);
    cin >> n;
    g[1] = 0, g[2] = 1;
    for (int i=3; i<=n; ++i) {
        g[i] = 1ll * C(i-2) * (i-1) % mod * g[i-2] % mod + 2ll * C(i-1) * g[i-1] % mod; 
        if(g[i] >= mod) g[i] -= mod;
    }
    for (int i=1; i<=n; ++i) {
        ans += 1ll * C(i) * g[i] % mod;
        if(ans >= mod) ans -= mod;
    }
    cout << ans; 
    return 0;
}
View Code

相关文章:

  • 2022-01-19
  • 2021-05-29
  • 2021-08-14
  • 2022-12-23
  • 2022-03-01
  • 2021-12-17
  • 2021-10-18
  • 2022-02-06
猜你喜欢
  • 2021-06-11
  • 2021-08-11
  • 2021-11-10
  • 2021-05-24
  • 2021-10-09
  • 2021-08-06
  • 2021-06-10
相关资源
相似解决方案