子序列

牛客网题目
题目描述

给出一个长度为n的序列,你需要计算出所有长度为k的子序列中,除最大最小数之外所有数的乘积相乘的结果

输入描述:

第一行一个整数T,表示数据组数。 对于每组数据,第一行两个整数N,k,含义如题所示

接下来一行N个整数,表示给出的序列

保证序列内的数互不相同

输出描述:

对于每组数据,输出一个整数表示答案,对109 + 7 取模 每组数据之间以换行分割

示例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的子序列为 (5,3,1) (5,3,4) (3,1,4) (5,1,4)
最终答案为3∗4∗3∗4=1443
在这里插入图片描述题解:
对于子序列一个数a,a会以三种形式存在
1.最大值
2.最小值
3.中间值
我们现将序列从小到大排序(从0开始),并不影响结果,但是有利于计算
a在长度为 k 的子序列中出现的次数为 Ck−1n−1(因为如果它出现在子序列中,那么总数还有 n−1 个 数字,序列的长度还有 k−1 个)
对于第一种情况,a作为最大值的下表为i,a之前的i个数都比a小,所选出的子序列一定有以下标i为结尾的,我们需要从前i个中选出k-1个,组成长度为k的子序列,个数为Ck-1i(组合数)
同理:ai 是最小值的情况的方法数为 Ck−1n−i−1
pi=Ck−1n−1−Ck−1i−Ck−1n−i−1 对于 ai这个数来说,它对答案的贡献为 apii
最终的答案为 :ans=∏n−1i=0apii

#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;
}

因为那个是指数,比如说 ab%p,可以用费马小定理 a(b%(p-1)) % p

posted @ 2020-04-18 13:14  回归梦想  阅读(224)  评论(0编辑  收藏  举报