zoukankan      html  css  js  c++  java
  • 题解 CF1342E Placing Rooks CF1342F Make It Ascending

    CF1342E

    题意

    给定一个(n imes 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)个不同的列,问总方案数。

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

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

    由于前面是假设每行放一个,当(k eq 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 eq j)),然后将(a_j+=a_i)并删除(a_i)。求将原序列变成严格单调上升的最少操作次数。(nleq 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
    ", 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 - i), puo(i, j, lim), fl = 0;
        }
        return 0;
    }
    
    
  • 相关阅读:
    Android 自定义ProgressDialog
    Android 设置TextView字体颜色
    Android 隐藏EditText的焦点
    Android TextView点击效果
    区间问题 codeforces 422c+hiho区间求差问
    hdu 5651 重复全排列+逆元
    hdu 1576
    C Looooops
    扩展欧几里得模板
    hdu 6025(女生赛)
  • 原文地址:https://www.cnblogs.com/Kylin-xy/p/CF1342E-CF1342F.html
Copyright © 2011-2022 走看看