Codeforces Global Round 24 D. Doremy's Pegging Game

首先我们可以假设最后一个删除的peg编号是x,那么可以发现每个编号结尾的方案数是一样的,可以只专注计算最后删1号peg的方案数,然后乘一下就好

然对于1来说,我们需要找到一个(x, y) 的组合,x和y之间允许剩pegs,但是1到x,以及y到1之间的pegs都被移除,这个状态在此时依然没有触碰blue peg,但在1被移除之后就会结束游戏,这个结果是可以通过组合数预先计算出来的

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <complex>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define MP make_pair
#define ll long long
#define ld long double
#define null NULL
#define all(a) a.begin(), a.end()
#define forn(i, n) for (int i = 0; i < n; ++i)
#define sz(a) (int)a.size()
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define bitCount(a)  __builtin_popcount(a)
template<class T> int gmax(T &a, T b) { if (b > a) { a = b; return 1; } return 0; }
template<class T> int gmin(T &a, T b) { if (b < a) { a = b; return 1; } return 0; }
using namespace std;
const int INF = 0x3f3f3f3f;
string to_string(string s) { return '"' + s + '"'; }
string to_string(const char* s) { return to_string((string) s); }
string to_string(bool b) { return (b ? "true" : "false"); }
template <typename A, typename B>
string to_string(pair<A, B> p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; }
template <typename A>
string to_string(A v) { bool first = true; string res = "{"; for (const auto &x : v) { if (!first) { res += ", "; } first = false; res += to_string(x); } res += "}"; return res; }
void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) { cerr << " " << to_string(H); debug_out(T...); }
#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

const int N = 5e3 + 5; 
ll Mul[N];
ll two[N];
ll prefix[N];
ll Cnm[N][N];

ll Pow(ll x, ll y, int MOD) {
    ll ans = 1;
    while(y) {
        if(y & 1) ans = 1ll * ans * x % MOD;
        x = 1ll * x * x % MOD;
        y >>= 1;
    }
    return ans;
}

ll C(int x, int y, int MOD) {
    // debug(x, y);
    if (x < y || y < 0 || x < 0) return 0;
    if(y == 0) return 1;
    return 1ll* Mul[x] * Pow(Mul[y] * Mul[x - y] % MOD, MOD - 2, MOD) % MOD;
}

int main() {
    int n, MOD;
    while(~scanf("%d %d", &n, &MOD)) {
        Mul[1] = 1; Mul[0] = 1;
        // two[0] = 1; two[1] = 2;
        for(int i = 2; i < n + 5; ++i) {
            Mul[i] = 1ll * Mul[i - 1] * i % MOD;
            // two[i] = 1ll * two[i - 1] * 2 % MOD; 
        }
        Cnm[0][0] = 1;
        for(int i = 1; i < n; ++i) {
            for(int j = 0; j <= i; ++j) {
                Cnm[i][j] = (Cnm[i - 1][j - 1] + Cnm[i - 1][j]) % MOD;
            }
        }

        prefix[0] = Mul[n - 2];
        // prefix[1] = Mul[n - 3];
        for(int i = 1; i <= n - 2; ++i) {
            prefix[i] = 0;
            for(int j = 0; j <= i - 1; ++j) {
                // debug(i - 1, j, n - 3 - j);
                prefix[i] = (prefix[i] + Cnm[i - 1][j] * Mul[n - 3 - j] % MOD) % MOD;
            }
            debug(prefix[i]);
        }

        ll ans = 0;
        // default use 1 as last one
        for(int i = 2; i <= n; ++i) {
            for(int j = i; j <= n; ++j) {
                int tmp = (n + 1) / 2 + i;
                if (j >= tmp) {
                    // large the half line
                    break;
                }

                int tmpr = n / 2 + j;
                if (tmp <= n + 1 && tmpr >= n + 1) {
                    // debug(i, j);
                    ans = (ans + prefix[j - i]) % MOD;
                }
            }
        }

        printf("%lld\n", ans * n % MOD);
    }
    return 0;
}
posted @ 2023-08-05 16:25  basasuya  阅读(121)  评论(0编辑  收藏  举报