Codeforces 840C On the Bench - 动态规划 - 组合数学

题目传送门

  传送门I

  传送门II

  传送门III

题目大意

  给定$n$个数,我们认为它们互不相同,即使它们数值上相等,问存在多少排列方式,使得任意两个相邻位置上的数的乘积不是完全平方数。

  显然一个正整数$x$可以被表示为$d_{1}\cdot s_{1}^{2}$,其中$d,s\in N_{+}$,$d$取最小值。

  另一个正整数$y$表示为$d_{2}\cdot s_{2}^{2}$。那么$xy$是完全平方数的充分必要条件是$d_{1} = d_{2}$。(可以先证明$d$不含平方因子,然后用反证法证明)

  然后问题可以转化成有$n$个互不相同的球,每个球被涂有一种颜色,要求将所有球排成一排,同种颜色的球不相邻的方案数。

  考虑设$f_{i, j}$表示当前考虑到第$i$种颜色,已经有$j$个连续的段。

  每次考虑放入一种颜色的所有球。主要有三种情况:

  1. 一个球被拿去连接两段球
  2. 一个球被放入了一个独立的段
  3. 一个球放在某一段的端点处

  我们枚举第一种情况的球的个数。假设第$i$种颜色有$c$个球,原本有$j$段球,现在我要拿$x$球作为第一种情况,拿$y$个球作为第二种情况。(这样根据之前有多少段计算现在有多少段)

  1. 对于第一部分,首先我需要选择$x$个球,然后在$j - 1$个间隙中选出$x$个间隙,再决定每个球放在哪个间隙。这一部分方案数是$\binom{c}{x}\binom{j - 1}{x}x!$
  2. 对于第二部分,我需要从剩下的$x - c$个球中选出$y$个球,我先将它排列好,然后分成$j - x$段插入间隙中(这个插入和上面的那种情况不同,这里不会连接两端点)。显然这一部分的方案数是$\binom{c - x}{y}\binom{y + j - x}{j - x}y!$
  3. 对于第三部分,剩下的球已经是确定的了,不用考虑。我只需要从$2(j - x)$个可选的位置中选择$c - x - y$个位置,然后排列一下把球放上去。

  时间复杂度$O(n^{3})$

Code

  1 /**
  2  * Codeforces
  3  * Problem#840C
  4  * Accepted
  5  * Time: 62ms
  6  * Memory: 1800k
  7  */
  8 #include <algorithm>
  9 #include <iostream>
 10 #include <cstdlib>
 11 #include <cstdio>
 12 using namespace std;
 13 typedef bool boolean;
 14 
 15 const int N = 305, M = 1e9 + 7;
 16 
 17 int add(int a, int b) {
 18     return ((a += b) >= M) ? (a - M) : (a);
 19 }
 20 
 21 int mul(int a, int b) {
 22     return (a * 1ll * b) % M;
 23 }
 24 
 25 void exgcd(int a, int b, int& x, int& y) {
 26     if (!b)
 27         x = 1, y = 0;
 28     else {
 29         exgcd(b, a % b, y, x);
 30         y -= (a / b) * x;
 31     }
 32 }
 33 
 34 int inv(int a, int n) {
 35     int x, y;
 36     exgcd(a, n, x, y);
 37     return (x < 0) ? (x + n) : (x);
 38 }
 39 
 40 int n;
 41 int ar[N];
 42 int f[N][N];
 43 int fac[N], _fac[N];
 44 int C[N << 1][N << 1];
 45 
 46 inline void init() {
 47     scanf("%d", &n);
 48     for (int i = 1, x, y; i <= n; i++) {
 49         scanf("%d", &x), y = 1;
 50         for (int p = 2, a = 0; p * p <= x; p++, a = 0) {
 51             while (!(x % p))
 52                 x /= p, a ^= 1;
 53             if (a)
 54                 y *= p;
 55         }
 56         if (x > 1)
 57             y *= x;
 58         ar[i] = y;
 59     }
 60 }
 61 
 62 inline void solve() {
 63     sort(ar + 1, ar + n + 1);
 64     C[0][0] = 1;
 65     for (int i = 1; i <= (n << 1); i++) {
 66         C[i][0] = C[i][i] = 1;
 67         for (int j = 1; j < i; j++)
 68             C[i][j] = add(C[i - 1][j - 1], C[i - 1][j]);
 69     }
 70 
 71     fac[0] = 1;
 72     for (int i = 1; i <= n; i++)
 73         fac[i] = mul(fac[i - 1], i);
 74     _fac[n] = inv(fac[n], M);
 75     for (int i = n; i; i--)
 76         _fac[i - 1] = mul(_fac[i], i);
 77 
 78     int t = 1;
 79     f[0][0] = 1;
 80     for (int i = 1, r = i; i <= n; i = r, t++) {
 81         while (r <= n && ar[r] == ar[i])
 82             r++;
 83         int cnt = r - i;
 84         for (int j = 0; j < i; j++) {
 85             for (int k = j; k <= j + cnt; k++) {
 86                 int c_indep = k - j, c_depen = cnt - c_indep;
 87                 int n_indep = mul(mul(C[cnt][c_indep], fac[c_indep]), C[c_indep + j][j]);
 88                 int n_depen = mul(C[j * 2][c_depen], fac[c_depen]);
 89                 f[t][k] = add(f[t][k], mul(f[t - 1][j], mul(n_indep, n_depen)));
 90             }
 91 //                f[t][k] = add(f[t][k], mul(f[t - 1][j], mul(mul(fac[k], _fac[j]), mul(C[j * 2][cnt - k + j], fac[cnt - k + j]))));
 92             for (int con = 1; con < j; con++) {
 93                 for (int k = j - con; k < r; k++) {
 94                     int c_indep = k - j + con, c_depen = cnt - con - c_indep;
 95                     if (c_depen < 0)
 96                         break;
 97                     int n_conne = mul(C[j - 1][con], mul(C[cnt][con], fac[con]));
 98                     int n_indep = mul(C[cnt - con][c_indep], mul(fac[c_indep], C[c_indep + j - con][j - con]));
 99                     int n_depen = mul(C[(j - con) * 2][c_depen], fac[c_depen]);
100                     f[t][k] = add(f[t][k], mul(f[t - 1][j], mul(n_conne, mul(n_indep, n_depen))));
101 //                    f[t][k] = add(f[t][k], mul(f[t - 1][j], mul(mul(C[j - 1][con], ), mul(fac[j + ind], mul(_fac[j], C[(j - con) * 2][dep])))));
102                 }
103             }
104          }
105 //        for (int i = 0; i < r; i++)
106 //            cerr << f[t][i] << " " ;
107 //        cerr << '\n';
108     }
109     printf("%d\n", f[t - 1][1]);
110 }
111 
112 int main() {
113     init();
114     solve();
115     return 0;
116 }

猜你喜欢

转载自www.cnblogs.com/yyf0309/p/9901886.html
今日推荐