【题解】P4456 [CQOI2018] 交错序列(数学递推)

P4456 CQOI2018 交错序列 - 洛谷 (luogu.com.cn)

时间复杂度线性。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 1e7 + 10;  
int fac[N], inv[N], P;

int qpow(int a, int b) {
    int c = 1;
    while (b) {
        if (b & 1) c = 1ll * c * a % P;
        a = 1ll * a * a % P;
        b >>= 1;
    }
    return c;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
	
	int n, a, b;
    cin >> n >> a >> b >> P;

    fac[0] = 1;
    for (int i = 1; i <= n + 1; i ++) {
        fac[i] = 1ll * fac[i - 1] * i % P;
    }

	inv[n + 1] = qpow(fac[n + 1], P - 2);   // (n+1)! 的逆元
	for (int i = n; i >= 0; i --)
    	inv[i] = 1ll * inv[i + 1] * (i + 1) % P;

    int ans = 0;
    // 枚举 1 的个数 i(即 y = i)
    for (int i = 0; i <= n; i ++) {
        // 交错序列中 1 不相邻,恰好有 i 个 1 的方案数为 C(n - i + 1, i)
        // 需要满足 i <= n - i + 1,即 2i <= n + 1,否则组合数为 0
        if (i <= n - i + 1) {
            // 组合数 C(n-i+1, i) = fac[n-i+1] * inv[i] * inv[n-2i+1] mod m
            // 这里 n-(i-1) = n-i+1,n-(i-1)-i = n-2i+1
            int comb = 1ll * fac[n - i + 1] * inv[i] % P * inv[n - i + 1 - i] % P;
            // 特征值:x = n - i(0 的个数),y = i(1 的个数)
            // 贡献 = 方案数 * (n-i)^a * i^b
            int term = 1ll * comb * qpow(n - i, a) % P * qpow(i, b) % P;
            ans = (ans + term) % P;
        }
    }

    cout << ans << "\n";
    return 0;
}
相关推荐
流浪0011 小时前
大厂 C/C++ 2023–2025 面试答案题汇总
开发语言·c++
青少儿编程课堂1 小时前
贪心算法进阶:区间调度与最少资源整合解析
c++·python·算法·贪心·信息学竞赛·区间调度
(Charon)1 小时前
【C++】 定时器入门:从定时任务到 epoll 驱动
开发语言·c++
青山木1 小时前
Hot 100 --- 划分字母区间
java·数据结构·算法·leetcode·贪心算法
励志不掉头发的内向程序员2 小时前
【LibreCAD 2D架构】鼠标点下的坐标为什么会被“吸”走?LibreCAD 对象捕捉系统解析
开发语言·c++·qt·学习·系统架构
Sunsets_Red2 小时前
浅谈扫描线
c++·算法·编程·题解·洛谷·扫描线·信息学竞赛
a187927218312 小时前
【算法】双指针与滑动窗口(一):框架总纲——三类问题、一个原理与判决书
算法·leetcode·区间·双指针·滑动窗口·原理·算法讲解
shehuiyuelaiyuehao2 小时前
算法42,模拟算法,模拟z字形变换
算法
朝朝辞暮i2 小时前
C++第一课
开发语言·c++·算法