当前位置: 首页 > news >正文

[NOI2020统一省选 A] 组合数问题 (推式子)

题意

给定四个整数 n , x , p , m n,x,p,m n,x,p,m,求
∑ i = 0 n f ( i ) × x i × ( n i ) \sum_{i=0}^{n}f(i)\times x^i\times \binom{n}{i} i=0nf(i)×xi×(in)
p p p 取模,其中 f ( x ) = a 0 + a 1 x + a 2 x 2 + ⋯ + a m x m f(x) = a_0 + a_1x + a_2x ^ 2 + \cdots + a_mx ^ m f(x)=a0+a1x+a2x2++amxm

1 ≤ n , x , p ≤ 1 0 9 , 0 ≤ a i ≤ 1 0 9 , 0 ≤ m ≤ min ⁡ ( n , 1 0 3 ) 1 \le n,x,p \le 10 ^ 9, 0 \le a_i \le 10 ^ 9, 0 \le m \le \min(n, 10 ^ 3) 1n,x,p109,0ai109,0mmin(n,103)

分析:

首先把 f ( i ) f(i) f(i) 带入原式
∑ i = 0 n x i × ( n i ) ∑ j = 0 m a j × i j \sum_{i=0}^{n} x^i\times \binom{n}{i} \sum_{j = 0} ^ {m} a_j \times i ^ {j} i=0nxi×(in)j=0maj×ij
看到 i j i ^ j ij,故想到展开 i j = ∑ k = 0 j { j k } i k ‾ i ^ j = \sum\limits_{k = 0} ^ {j} {j \brace k} i ^ {\underline k} ij=k=0j{kj}ik

∑ i = 0 n x i × ( n i ) ∑ j = 0 m a j ∑ k = 0 j { j k } × i ! ( i − k ) ! \sum_{i=0}^{n} x^i\times \binom{n}{i} \sum_{j = 0} ^ {m} a_j \sum_{k = 0} ^ {j} {j \brace k} \times \frac{i!}{(i - k)!} i=0nxi×(in)j=0majk=0j{kj}×(ik)!i!

把前面的 ( n i ) \dbinom{n}{i} (in) 放到最后面化简

∑ i = 0 n x i ∑ j = 0 m a j ∑ k = 0 j { j k } × n ! i ! × ( n − i ) ! × i ! ( i − k ) ! = ∑ i = 0 n x i ∑ j = 0 m a j ∑ k = 0 j { j k } × n ! ( n − i ) ! × ( i − k ) ! \sum_{i=0}^{n} x^i \sum_{j = 0} ^ {m} a_j \sum_{k = 0} ^ {j} {j \brace k} \times\dfrac{n!}{i! \times (n - i)!} \times \frac{i!}{(i - k)!} \\\\ = \sum_{i=0}^{n} x^i \sum_{j = 0} ^ {m} a_j \sum_{k = 0} ^ {j} {j \brace k} \times\dfrac{n!}{(n - i)! \times (i - k)!} i=0nxij=0majk=0j{kj}×i!×(ni)!n!×(ik)!i!=i=0nxij=0majk=0j{kj}×(ni)!×(ik)!n!

考虑凑组合数 ( n − k n − i ) = ( n − k ) ! ( n − i ) ! × ( i − k ) ! \dbinom{n - k}{n - i} = \dfrac{(n - k)!}{(n - i)! \times (i - k)!} (nink)=(ni)!×(ik)!(nk)!,所以分式上下同乘 ( n − k ) ! (n - k)! (nk)!,即
∑ i = 0 n x i ∑ j = 0 m a j ∑ k = 0 j { j k } × ( n − k n − i ) × n k ‾ \sum_{i=0}^{n} x^i \sum_{j = 0} ^ {m} a_j \sum_{k = 0} ^ {j} {j \brace k} \times \binom{n - k}{n - i} \times n ^ {\underline k} i=0nxij=0majk=0j{kj}×(nink)×nk
交换求和次序,将 i i i 放到最后求和

∑ j = 0 m a j ∑ k = 0 j { j k } × n k ‾ ∑ i = 0 n x i × ( n − k n − i ) = ∑ j = 0 m a j ∑ k = 0 j { j k } × n k ‾ ∑ i = 0 n x i × ( n − k i − k ) = ∑ j = 0 m a j ∑ k = 0 j { j k } × n k ‾ ∑ i = k n x i × ( n − k i − k ) \sum_{j = 0} ^ {m} a_{j} \sum_{k = 0} ^ {j} {j \brace k} \times n ^ {\underline k} \sum_{i=0}^{n} x^i \times \binom{n - k}{n - i} \\\\ = \sum_{j = 0} ^ {m} a_j \sum_{k = 0} ^ {j} {j \brace k} \times n ^ {\underline k} \sum_{i=0}^{n} x^i \times \binom{n - k}{i - k} \\\\ = \sum_{j = 0} ^ {m} a_j \sum_{k = 0} ^ {j} {j \brace k} \times n ^ {\underline k} \sum_{i=k}^{n} x^i \times \binom{n - k}{i - k} j=0majk=0j{kj}×nki=0nxi×(nink)=j=0majk=0j{kj}×nki=0nxi×(iknk)=j=0majk=0j{kj}×nki=knxi×(iknk)

做变换 ( i − k ) → i (i - k) \rightarrow i (ik)i

∑ j = 0 m a j ∑ k = 0 j { j k } × n k ‾ ∑ i = 0 n − k x i + k × ( n − k i ) = ∑ j = 0 m a j ∑ k = 0 j { j k } × n k ‾ × x k ∑ i = 0 n − k x i × ( n − k i ) \sum_{j = 0} ^ {m} a_j \sum_{k = 0} ^ {j} {j \brace k} \times n ^ {\underline k} \sum_{i=0}^{n - k} x^{i + k} \times \binom{n - k}{i} \\\\ = \sum_{j = 0} ^ {m} a_j \sum_{k = 0} ^ {j} {j \brace k} \times n ^ {\underline k} \times x ^ {k} \sum_{i=0}^{n - k} x^{i} \times \binom{n - k}{i} j=0majk=0j{kj}×nki=0nkxi+k×(ink)=j=0majk=0j{kj}×nk×xki=0nkxi×(ink)

考虑二项式展开 ( a + b ) n = ∑ i = 0 n ( n i ) a i b n − i (a + b) ^ n = \sum\limits_{i = 0} ^ {n} \dbinom{n}{i} a ^ {i} b ^ {n - i} (a+b)n=i=0n(in)aibni,所以 ∑ i = 0 n − k x i × ( n − k i ) = ( 1 + x ) n − k \sum\limits_{i=0}^{n - k} x^{i} \times \dbinom{n - k}{i} = (1 + x) ^ {n - k} i=0nkxi×(ink)=(1+x)nk,故式子变为
∑ j = 0 m a j ∑ k = 0 j { j k } × n k ‾ × x k × ( 1 + x ) n − k \sum_{j = 0} ^ {m} a_j \sum_{k = 0} ^ {j} {j \brace k} \times n ^ {\underline k} \times x ^ {k} \times (1 + x) ^ {n - k} j=0majk=0j{kj}×nk×xk×(1+x)nk
这样式子就变为 O ( m 2 ) O(m ^ 2) O(m2) 了,第二类斯特林数可以预处理,下降幂可以线性维护。

代码:

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 1e3;
int mod;
int norm(int x) {
    if (x < 0) {
        x += mod;
    }
    if (x >= mod) {
        x -= mod;
    }
    return x;
}
template<class T>
T power(T a, int b) {
    T res = 1;
    for (; b; b /= 2, a *= a) {
        if (b % 2) {
            res *= a;
        }
    }
    return res;
}
struct Z {
    int x;
    Z(int x = 0) : x(norm(x)) {}
    int val() const {
        return x;
    }
    Z operator-() const {
        return Z(norm(mod - x));
    }
    Z inv() const {
        assert(x != 0);
        return power(*this, mod - 2);
    }
    Z &operator*=(const Z &rhs) {
        x = i64(x) * rhs.x % mod;
        return *this;
    }
    Z &operator+=(const Z &rhs) {
        x = norm(x + rhs.x);
        return *this;
    }
    Z &operator-=(const Z &rhs) {
        x = norm(x - rhs.x);
        return *this;
    }
    Z &operator/=(const Z &rhs) {
        return *this *= rhs.inv();
    }
    friend Z operator*(const Z &lhs, const Z &rhs) {
        Z res = lhs;
        res *= rhs;
        return res;
    }
    friend Z operator+(const Z &lhs, const Z &rhs) {
        Z res = lhs;
        res += rhs;
        return res;
    }
    friend Z operator-(const Z &lhs, const Z &rhs) {
        Z res = lhs;
        res -= rhs;
        return res;
    }
    friend Z operator/(const Z &lhs, const Z &rhs) {
        Z res = lhs;
        res /= rhs;
        return res;
    }
    friend istream &operator>>(istream &is, Z &a) {
        i64 v;
        is >> v;
        a = Z(v);
        return is;
    }
    friend ostream &operator<<(ostream &os, const Z &a) {
        return os << a.val();
    }
};
vector<vector<Z>> stirling(N + 1, vector<Z>(N + 1));
void init() {
    stirling[0][0] = 1;
    for (int i = 1; i <= N; i ++) {
        for (int j = 1; j <= i; j ++) {
            stirling[i][j] = stirling[i - 1][j - 1] + j * stirling[i - 1][j];
        }
    }
}
signed main() {
    cin.tie(0) -> sync_with_stdio(0);
    int n, x, m;
    cin >> n >> x >> mod >> m;
    init();
    vector<Z> a(m + 1);
    for (int i = 0; i <= m; i ++) {
        cin >> a[i];
    }
    Z res;
    for (int j = 0; j <= m; j ++) {
        Z sum = 1;
        for (int k = 0, cnt = n; k <= j; k ++, cnt --) {
            res += a[j] * stirling[j][k] * power(Z(x), k) * sum * power(Z(1 + x), n - k);
            sum *= cnt;
        }
    }
    cout << res << "\n";
}

相关文章:

  • 通过js 获取最近3天、1周、1个月、3个月、半年、1年的时间
  • LeaRun.Java工作流引擎 快速开发业务流程
  • 为什么大家都开始做游戏化产品?
  • python open file way
  • 跨域访问错误的这一种解决方法
  • 一位工作多年的测试人告诉你哪些抓包工具指的推荐~
  • Redux学习与使用
  • 计算机组成原理知识总结(九)并行组织与结构
  • 带内全双工水声通信系统自干扰抵消技术研究框架与思路
  • 关于在使用elementui的tabs组件进行切换组件时会闪屏的解决方案
  • 网站被劫持了怎么办?
  • 二、字符串 String
  • Python数据类型转换
  • Protobuf 和JSON 性能分析
  • DCA培训心得笔记(二)
  • 「译」Node.js Streams 基础
  • 【面试系列】之二:关于js原型
  • 30天自制操作系统-2
  • C++类的相互关联
  • CentOS7简单部署NFS
  • es6--symbol
  • HTTP中GET与POST的区别 99%的错误认识
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • javascript 哈希表
  • javascript 总结(常用工具类的封装)
  • MQ框架的比较
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 前端技术周刊 2019-01-14:客户端存储
  • 微信小程序开发问题汇总
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • # centos7下FFmpeg环境部署记录
  • #经典论文 异质山坡的物理模型 2 有效导水率
  • (day 12)JavaScript学习笔记(数组3)
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (六)软件测试分工
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (转)LINQ之路
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • (转)平衡树
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • .NET CF命令行调试器MDbg入门(一)
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .net反编译工具
  • .net连接MySQL的方法
  • .NET微信公众号开发-2.0创建自定义菜单
  • .NET与 java通用的3DES加密解密方法
  • .net中的Queue和Stack
  • @Async注解的坑,小心
  • [1159]adb判断手机屏幕状态并点亮屏幕
  • [BZOJ 3282] Tree 【LCT】
  • [BZOJ3211]:花神游历各国(小清新线段树)
  • [FC][常见Mapper IRQ研究]