F-子序列(組合數,打表,擴充套件尤拉,容斥)
阿新 • • 發佈:2018-12-28
題目描述
給出一個長度為n的序列,你需要計算出所有長度為k的子序列中,除最大最小數之外所有數的乘積相乘的結果
輸入描述:
第一行一個整數T,表示資料組數。
對於每組資料,第一行兩個整數N,k,含義如題所示
接下來一行N個整數,表示給出的序列
保證序列內的數互不相同
輸出描述:
對於每組資料,輸出一個整數表示答案,對取模
每組資料之間以換行分割
輸入
3
4 3
5 3 1 4
5 4
3 7 5 2 1
10 3
100 1020 2050 102 12 235 4 57 32135 54354
輸出
144
81000
521918013
說明
第一組資料解釋
所有長度為3的子序列為(5,3,1)(5,3,4)(3,1,4)(5,1,4)
最終答案為 3*4*3*4 = 144
AC
容斥求出每個數利用的個數,總的出現次數-這個數作為最小值出現-這個數作為最大值出現
求組合數可以打表,組合數的數值很大而且結果要作為指數計算,這裡就要用到擴充套件尤拉
#include <iostream>
#include <stdio.h>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 1015
#define ll long long
using namespace std;
ll c[N][N], mod = 1e9 + 7, a[N];
ll C(int n, int m) {
if (m > n || n <= 0)
return 0;
else
return c[n][m];
}
ll quick_pow(ll a, ll b) {
ll ans = 1;
while (b) {
if (b & 1) {
ans = ans * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return ans;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
// 組合數打表
c[0][0] = 1;
for (int i = 1; i < N; ++i) {
c[i][0] = 1;
for (int j = 1; j <= i; ++j) {
// 擴充套件尤拉
c[i][j] = c[i - 1][j] + c[i - 1][j - 1] % (mod - 1);
}
}
int t;
scanf("%d", &t);
while (t--) {
int n, k;
scanf("%d%d", &n, &k);
for (int i = 0; i < n; ++i) {
scanf("%lld", &a[i]);
}
sort(a, a + n);
ll ans = 1;
for (int i = 0; i < n; ++i) {
ll mi = c[n - 1][k - 1] - C(n - i - 1, k - 1) - C(i, k - 1);
// 擴充套件尤拉
mi = (mi + mod - 1) % (mod - 1);
ans = quick_pow(a[i], mi) * ans % mod;
}
printf("%lld\n", ans);
}
return 0;
}