8.30 牛客OI赛制测试赛1 F题 子序列

题目描述

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

输入描述:

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

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

保证序列内的数互不相同

输出描述:

对于每组数据,输出一个整数表示答案,对
取模
每组数据之间以换行分割
链接:https://www.nowcoder.com/acm/contest/181/F
来源:牛客网

输入

复制
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)
五眼看过去还要容斥,减去作为最大最小值次数
六眼看过去可以排个序,和前面搭配是作为最大值,和后面搭配作为最小值
七眼看过去还要一个快速幂
 
然后手打,结果挂了。AK失败。
好吧,其实方法一点没错,但是细节出了问题。
组合数n^2预处理嘛,习惯性对p=1e9+7取模。
以前一直是这样。。。
 
但是,以前组合数是乘数,现在组合数可是指数啊!!
指数怎么能对p取模呢??
 
但是指数可以对p-1取模。
因为这里p是质数,a^(p-1)=1 mod p(费马搞死你)
所以,指数减掉若干个p-1,并不影响。
当一般地,(a,p)=1而p不是质数,就欧拉定理,a^(phi(p))=1 mod p呗
 
 
(学信竞1年来,头一次知道对指数取模可以mod phi(p) -_-||)
Code:
#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]+2*(mod-1))%(mod-1);
            
            ans=(ans*qm(a[i],ci))%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
 注意取余运算的正确性,不是随便瞎取模都行的,也不是一定都对p取模

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/9560987.html