题干:
题目描述
给出一个长度为n的序列,你需要计算出所有长度为k的子序列中,除最大最小数之外所有数的乘积相乘的结果
输入描述:
第一行一个整数T,表示数据组数。
对于每组数据,第一行两个整数N,k,含义如题所示接下来一行N个整数,表示给出的序列保证序列内的数互不相同
输出描述:
对于每组数据,输出一个整数表示答案,对取模
每组数据之间以换行分割
示例1
输入
复制
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的子序列为
最终答案为
备注:
对于的数据:
对于的数据:
对于的数据:
保证序列中的元素互不相同且,
解题报告:
首先暴力可以n^2。思路就是要算每一个数的贡献,也就是每一个数的出现次数。
总次数是C(n-1,k-1)。我们可以枚举 在前面选了多少个,在后面选了多少个。但是这样复杂度就成了O(nk)了,,也高不了哪去。所以想个办法优化,不难想到,可以求问题的反面,容斥一下,用总次数减去作为最大最小值次数。可以排个序,和前面搭配是作为最大值,和后面搭配作为最小值。
注意,以前组合数是乘数,现在组合数是指数,不要习惯性对p=1e9+7取模。
指数可以对p-1取模。因为这里p是质数,a^(p-1)=1 mod p(费马小定理)
所以,指数减掉若干个p-1,并不影响。
当一般地,(a,p)=1而p不是质数,就欧拉定理,a^(phi(p))=1 mod p所以对phi(p)取模
AC代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2005;
const int mod=1e9+7;
typedef long long ll;
int n,q,k;
ll a[N];
ll c[N][N];
ll qm(ll x,ll y) {ll ret=1;while(y) {if(y%2==1) ret=(ret*x)%mod;x=(x*x)%mod;y/=2;}if(ret<0) ret=(ret+mod)%mod;return ret%mod;
}
signed main() {for(int i=0; i<=2001; i++) {c[i][0]=1;for(int j=1; j<=i; j++) {c[i][j]=(c[i-1][j-1]+c[i-1][j])%(mod-1);}}scanf("%lld",&q);while(q--) {scanf("%lld%lld",&n,&k);for(int i=1; i<=n; i++)scanf("%lld",&a[i]);sort(a+1,a+n+1);ll ans=1;for(int i=1; i<=n; i++) {ll ci=(c[n-1][k-1]-c[i-1][k-1]-c[n-i][k-1]+5*(mod-1))%(mod-1);ans=(ans*qm(a[i],ci))%mod;}printf("%lld\n",ans);}return 0;
}
参考博客:链接