牛客OI赛制测试赛1 F子序列(组合数学+容斥)
Posted ITAK
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客OI赛制测试赛1 F子序列(组合数学+容斥)相关的知识,希望对你有一定的参考价值。
题目描述
给出一个长度为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的子序列为 最终答案为
备注:
对于的数据:
对于的数据:
对于的数据:
保证序列中的元素互不相同且,
解题思路:
对于每个数字在长度为
k
k
的子序列中出现的次数为 次,这个地方解释一下,对于
ai
a
i
这个数来说,如果它出现在子序列中,那么总数还有
n−1
n
−
1
个 数字,序列的长度还有
k−1
k
−
1
个,所以结果为
Ck−1n−1
C
n
−
1
k
−
1
。
如果
ai
a
i
这个数字需要计入结果中,那么
ai
a
i
一定不是最大值或者最小值,所以我们从反面考虑:
1) 假设
ai
a
i
是最大值的情况,那么我们首先将这个数组进行排序(下标从
0
0
开始),那么如果 是最大值的话,那么一定有下标
i
i
作为下标结束的末尾,我们只需要从前 个数中选取
k−1
k
−
1
个数即可,方法数为
Ck−1i
C
i
k
−
1
2) 同理,
ai
a
i
是最小值的情况的方法数为
Ck−1n−i−1
C
n
−
i
−
1
k
−
1
综上,令
pi=Ck−1n−1−Ck−1i−Ck−1n−i−1
p
i
=
C
n
−
1
k
−
1
−
C
i
k
−
1
−
C
n
−
i
−
1
k
−
1
对于
ai
a
i
这个数来说,它对答案的贡献为
apii
a
i
p
i
最终的答案为 :
ans=∏n−1i=0apii
a
n
s
=
∏
i
=
0
n
−
1
a
i
p
i
最后,只需要预处理组合数取模即可。
代码如下
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
typedef long long LL;
const LL MOD = 1e9+7;
const int MAXN = 1e3+5;
int a[MAXN];
LL Pow(LL a, LL b)
LL ans = 1;
while(b)
if(b&1) ans=ans*a%MOD;
b>>=1;
a=a*a%MOD;
return ans;
LL c[MAXN][MAXN];
void Init()
memset(c, 0, sizeof c);
for(int i=0; i<MAXN; 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 main()
Init();
int T; cin>>T;
while(T--)
int n, k; cin>>n>>k;
for(int i=0; i<n; i++) cin>>a[i];
sort(a, a+n);
LL tmp = c[n-1][k-1];
LL ans = 1;
for(int i=0; i<n; i++)
LL b = tmp-c[i][k-1]-c[n-i-1][k-1];
b = (b%(MOD-1)+(MOD-1))%(MOD-1);
ans = ans*Pow(a[i], b)%MOD;
cout<<ans<<endl;
return 0;
以上是关于牛客OI赛制测试赛1 F子序列(组合数学+容斥)的主要内容,如果未能解决你的问题,请参考以下文章
2021牛客暑期多校训练营5 D.Double Strings(容斥dp)