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