链接:https://www.nowcoder.com/acm/contest/181/F
来源:牛客网
题目描述
给出一个长度为n的序列,你需要计算出所有长度为k的子序列中,除最大最小数之外所有数的乘积相乘的结果
题解
每个数的贡献容斥一下就好
对于每个数来说,这个数的贡献 = = = 所有含这个数的子序列的个数 − - − 含这个数并且这个数是子序列的最小值的个数 − - − 含这个数并且这个数是子序列的最大值的个数
不难发现,需要先排序
知识整合
欧拉降幂
a b ≡ a b % φ ( p ) ( m o d p ) a ^ b \equiv a ^ {b \% \varphi(p)} (mod~~ p) ab≡ab%φ(p)(mod p)
欧拉降幂是幂次对 φ ( p ) \varphi(p) φ(p)取模,而非 p p p
b b b中所有的项的预处理都要对 φ ( p ) \varphi(p) φ(p)取模
杨辉三角
简单的预处理
#include<iostream>
#include<algorithm>
using namespace std;
#define mod 1000000007
typedef long long ll;
const int N = 1e3 + 10;
ll u[N];
ll c[N][N];
ll qpow(ll a, ll b, ll p) {
ll res = 1;
while (b) {
if (b & 1) {
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
void init_com(const int n = 1e3) {
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= i; j++) {
if (i == j || j == 0) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % (mod - 1);
}
}
}
int main() {
//杨辉三角初始化组合数
init_com();
int T; cin >> T;
while (T--) {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> u[i];
}
sort(u + 1, u + n + 1);
ll ans = 1;
for (int i = 1; i <= n; i++) {
//容斥
//这个数的贡献 = 含这个数的所有情况 - 以u[i]最大 - u[i]最小
ll t = c[n - 1][k - 1] - c[i - 1][k - 1] - c[n - i][k - 1];
//欧拉定理 a^b = a^(b % (p - 1))
//所以幂次需要对(mod - 1)取模
//由于幂次有组合数,所以预处理组合数时,对(mod - 1)取模就行
t = (t % (mod - 1) + (mod - 1)) % (mod - 1);
//答案是对mod取模的
ans = ans * qpow(u[i], t, mod) % mod;
}
cout << ans << endl;
}
return 0;
}