码迷,mamicode.com
首页 > 其他好文 > 详细

题解 CF1342E Placing Rooks CF1342F Make It Ascending

时间:2020-09-17 16:41:27      阅读:27      评论:0      收藏:0      [点我收藏+]

标签:fine   元素   最小   namespace   algorithm   题意   end   阶乘   +=   

CF1342E

题意

给定一个\(n \times n\)的棋盘,要求放\(n\)个棋,使得所有格子都在攻击范围内,且恰好有\(k\)对互相攻击,求方案数对\(998244353\)取模的结果。两个棋互相攻击当且仅当它们在同一行或者同一列,且中间没有其他棋子。\(n \leq 200000\)

题解

发现每个格子都必须被覆盖,所以每行或者每列应该恰好放一个棋子,假设是每行放一个。我们发现在某行或者某列若有\(x\)个棋子,那么互相攻击棋子对的贡献是\(x-1\)。假设我们一共放\(m\)列,每列放\(a_i\)个,那么总贡献为\(\sum_{i=1}^m a_i -1 =k\),又因为一共有\(n\)个棋子,所以\(\sum_{i=1}^m a_i =n\),差分得\(m=n-k\)

现在就相当于\(n\)个不同行的棋子,放进\(n-k\)个不同的列,问总方案数。

第二类斯特林数里面的盒子是相同的,但是这题不同,所以要乘上一个阶乘。所以答案是:

\[\binom{n}{n-k} \begin{Bmatrix} n \\n-k \end{Bmatrix} (n-k)! \=\binom{n}{n-k} \sum_{i=0}^k (-1)^k \binom{k}{i} (k-i)^n \]

由于前面是假设每行放一个,当\(k \neq 0\)的时候每行放一个和每列放一个不等价,答案要乘\(2\)

代码

#include <stdio.h>
#define it register int
#define ct const int
#define il inline
#define P 998244353
const int N = 1000005;
int n, ans, fac[N], ifac[N], inv[N];
long long K;
il int ksm(it x, it L) { it ans = 1; while (L) L& 1 ? ans = (0ll + ans) * x % P : 0, x = (0ll + x) * x % P, L >>= 1; return ans;}
il int C(ct n, ct m) { return m < 0 || n < m ? 0 : (0ll + fac[n]) * ifac[m] % P * ifac[n - m] % P; }
int main() {
    scanf("%d%lld", &n, &K);
    if (K >= n) return putchar(‘0‘), 0;
    K = n - K; it i;
    for (i = 2, fac[0] = fac[1] = ifac[0] = ifac[1] = inv[0] = inv[1] = 1; i <= n; ++i)
        fac[i] = (0ll + fac[i - 1]) * i % P, inv[i] = (0ll + inv[P % i]) * (P - P / i) % P, ifac[i] = (0ll + ifac[i - 1]) * inv[i] % P;
    for (i = 0; i <= K; ++i) ans = (ans + (0ll + ksm(K - i, n)) * (i & 1 ? P - C(K, i) : C(K, i))) % P;
    printf("%d", (K < n ? 2ll : 1ll) * (0ll + ans) * C(n, K) % P);
    return 0;
}

CF1342F

题意

给定一个长度为\(n\)的序列\(a\),每次可以选择两个位置 \(i,j(i\neq j)\),然后将\(a_j+=a_i\)并删除\(a_i\)。求将原序列变成严格单调上升的最少操作次数。\(n\leq 15\)

题解

相当于把序列划分成若干组,每组以某个元素为基础位置,其余元素都累加到这个基础位置上,问最小操作次数。

\(f[i][j][s]\) 表示枚举到第 \(i\) 组,第 \(i\) 组以 \(j\) 为基础位置,前 \(i\) 组的状态集合为 \(s\) 的情况下第 \(i\) 组的最小值。

转移时枚举一个不属于任何集合的元素,考虑加到第 \(i\) 个集合里或者新建第 \(i+1\) 个集合,注意第 \(i+1\) 个集合的基础位置的值必须比第\(i\)个大。

输出路径只需要在转移的时候记一下是从哪个状态转移过来的。

代码


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define it register int
#define ct const int
#define il inline
using namespace std;
const int N = 1 << 15, inf = 2139062143;
int T, f[16][16][N], a[N], pw[N], sum[N], n, lim;
pair<int, int> pre[16][16][N];
il void del(it x) { while (x < n) --a[x], ++x; }
il void puo(ct i, ct j, ct s) {
    if (!s) return;
    ct ss = s ^ pre[i][j][s].first;
    for (it x = 0; x < n; ++x)
        if (x != j - 1 && (ss & pw[x]))
            printf("%d %d\n", a[x], a[j - 1]), del(x);
    puo(i - 1, pre[i][j][s].second, pre[i][j][s].first);
}
int main() {
    scanf("%d", &T); it i, j, s, ss, tj, k, fl;
    for (i = pw[0] = 1; i <= 30; ++i) pw[i] = pw[i - 1] << 1;
    while (T--) {
        scanf("%d", &n), lim = 1 << n;
        for (i = 0; i <= n; ++i) for (j = 0; j <= n; ++j) memset(f[i][j], 127, lim << 2);
        for (i = 0; i < lim; ++i) sum[i] = 0;
        for (i = 0; i < n; ++i) scanf("%d", &j), sum[pw[i]] = j, a[i] = i + 1;
        for (i = 0; i < lim; ++i) sum[i] = sum[i & (i - 1)] + sum[i & (-i)];
        for (i = f[0][0][0] = 0, --lim; i < n; ++i)
            for (s = 0; s <= lim; ++s)
                for (j = 0; j < n; ++j)
                    if (f[i][j][s] < inf)
                        for (ss = lim ^ s, k = ss; k; k = (k - 1) & ss)
                            if (sum[k] > f[i][j][s] && (k >> j))
                                if (f[i + 1][tj = j + __builtin_ctz(k >> j) + 1][s | k] > sum[k])
                                    f[i + 1][tj][s | k] = sum[k], pre[i + 1][tj][s | k] = make_pair(s, j);
        for (i = n, fl = 1; fl && i; --i)
            for (j = 1; fl && j <= n; ++j)
                if (f[i][j][lim] != inf) printf("%d\n", n - i), puo(i, j, lim), fl = 0;
    }
    return 0;
}

题解 CF1342E Placing Rooks CF1342F Make It Ascending

标签:fine   元素   最小   namespace   algorithm   题意   end   阶乘   +=   

原文地址:https://www.cnblogs.com/Kylin-xy/p/CF1342E-CF1342F.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!