【NOIP模拟赛】Pickad 锄奸

来源:互联网 发布:怎么看手机网络制式 编辑:程序博客网 时间:2024/06/06 01:25

Pickad 锄奸


  • Description

两军对垒,敌方派出了N个武将前来叫板,你选定了N个手下,打算和对方决一死战。
实际上,你并不想赢下这场战斗,因为根据你的眼线汇报,这N个人都已经暗中投奔敌方。所以,你打算让这些人都死在战场上,以绝后患。
我们把两个武将的战斗简化为战斗力的比较,战斗力高的人赢。你已经知道了对面N个武将的战斗力,分别是Si。
现在你可以任意指定你的武将的战斗力为任意正整数。指定之后,如果你可以把这些武将和敌方的武将一一对应,使得在所有战斗中你的武将都没有赢,那么这个战斗力方案合法。剩下的问题,就是有多少种合法方案了。

  • Input Format

第一行一个整数T,表示数据组数
接下来T行,每行一个N,然后N个整数Si

  • Output Format

T行,每行一个整数表示答案,模10^9+7。

  • Sample Input

4
2 1 2
9 2 2 2 2 2 2 2 2 2
3 5 1 2
5 3 14159 2653589 7 932

  • Sample Output

3
512
34
353127147

  • Hint

【样例解释】
对于第一组数据,合法方案分别是:(1,1),(1,2),(2,1)
对于第二组数据,每个武将的武力值为1或者2,根据乘法原理,答案是2^9=512

【数据范围】
20%的数据,N ≤ 7,Si ≤ 10。
40%的数据,N ≤ 100,Si ≤ 100。
70%的数据,N ≤ 200,Si ≤ 10^9。
100%的数据,N ≤ 1 000,1 ≤ Si ≤ 10^9,T ≤ 5。


  • 分析

以下来自题解:
首先把Si排个序,如果方案可行肯定是把自己人的战斗力也从小往大排然后一一对应
很明显,所有人的战斗力都在[1,Sn]之间。
现在用F[i]表示i个将军,能够匹配S1到Si的方案数。很明显所有人战斗力不能超过Si,不考虑非法情况,答案就是si^i。
现在考虑F[i]中所有不满足要求的情况,一定是匹配到Sj-1(1<=j<=i-1),找不到一个匹配Sj的点
无法匹配Sj,也就是说剩下的i-j+1个人的战斗力在[S[j]+1,Sn]之间自由分配,方案数是(s[n]-s[j])^(i-j+1)。前面j-1个点的方案是F[j-1]。要把这j-1个人放在i个位置中,方案是C(I,j-1)。
所以有F[i]=S[i]^i-Sigma(F[j-1]*(S[i]-S[j])^(i-j+1)*C(i,j-1)) [1<=j<=i-1]。
预处理组合数,有幂的地方套快速幂。
复杂度是O(T*n^2 log S)。

处理组合数的时候,有一种不用逆元的方法。因为我们需要的是一大堆连续的组合数,所以我们可以用杨辉三角之类的东西搞一搞。要注意一点是,杨辉三角处理出来的C数组和组合C是不一样的,组合数C(i,j)应该是数组的C[i-j+1][j+1]


#include <queue>#include <stack>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const long long Mod=1000000007;long long C[1006][1006],a[1006],F[1006];int n,T;long long Power(long long a,long long b){    long long s=1;    for (;b;b>>=1){        if (b&1) s=(s*a)%Mod;        a=(a*a)%Mod;    }    return s;}int main(){    freopen("3.in","r",stdin);    freopen("3.out","w",stdout);    for (int i=1;i<=1002;i++) C[i][1]=C[1][i]=1;    for (int i=2;i<=1002;i++)        for (int j=2;j<=1000;j++) C[i][j]=(C[i-1][j]+C[i][j-1])%Mod;    for (scanf("%d",&T);T;T--){        scanf("%d",&n);        for (int i=1;i<=n;i++) scanf("%lld",&a[i]);        sort(a+1,a+1+n);        F[0]=1; F[1]=a[1];        for (int i=2;i<=n;i++){            a[i]%=Mod;            F[i]=Power(a[i],i);            for (int j=1;j<i;j++){                long long S=(((F[j-1]*Power(a[i]-a[j],i-j+1))%Mod)*C[i-j+2][j])%Mod;                F[i]=(F[i]-S+Mod)%Mod;            }        }        printf("%lld\n",F[n]);    }    fclose(stdin); fclose(stdout);    return 0;}
0 0
原创粉丝点击