本质数学题

我们可以求出这个这个排列里面有x = n//3个3的倍数,我们需要y = n//2个3的倍数

那么我们可以在x中选y - x个挪到外面,在外面n - x 个里面选y - x个放进来,然后里面的全排一下,外面的全排一下就好了喵

这道题的难点全在求逆元和组合数上面了()

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 i128;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int MOD = 1e9 + 7;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
#define int ll

ll fact[N];    // 阶乘
ll infact[N];  // 阶乘的逆元

// 快速幂:计算 a^b % p
ll qpow(ll a, ll b) {
    ll res = 1;
    while (b) {
        if (b & 1) res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}

// 初始化函数:O(N) 时间复杂度
void init() {
    fact[0] = infact[0] = 1;
    
    // 1. 预处理阶乘
    for (int i = 1; i < N; i++) {
        fact[i] = fact[i - 1] * i % MOD;
    }

    // 2. 算出最大阶乘的逆元 (费马小定理)
    infact[N - 1] = qpow(fact[N - 1], MOD - 2);

    // 3. 线性倒推所有逆元 (核心技巧: 1/i! = 1/(i+1)! * (i+1))
    for (int i = N - 2; i >= 1; i--) {
        infact[i] = infact[i + 1] * (i + 1) % MOD;
    }
}

// 计算组合数 C(n, m)
ll C(int n, int m) {
    if (m < 0 || m > n) return 0;
    return fact[n] * infact[m] % MOD * infact[n - m] % MOD;
}

// 计算排列数 A(n, m)
ll A(int n, int m) {
    if (m < 0 || m > n) return 0;
    return fact[n] * infact[n - m] % MOD;
}

void solve()
{	
    int n;
    cin>>n;
    int x = n / 3;
    if (x == 0) 
    {
        cout<<0<<'\n';
        return;
    }
    int need = n / 2;
    int y = n - x;
    int ans = ((C(y,need - x) * C(x,need - x) % MOD) * fact[x] % MOD) * fact[y] % MOD;
    cout<<ans<<'\n';

    return;
}
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    init();
    int _ = 1;
    //std::cin>>_;
    while (_--)
    {
        solve();
    }
    return 0;
}
/*
    ∧_∧
   (。•́︿•̀。)
   /づ正数与负数
 都要开心计算哦
*/