【锄奸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

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

Sample Output

3
512
34
353127147

Hint

数据范围

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

无法匹配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)。

       (copy大神的题解)

详见代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
long long i,j,k,l,m,n,mo=1000000007,T;
long long f[1005],c[1005][1005],a[1005];
long long qsm(long long a,long long b)
  {
    long long x=1;
    for (;b;b>>=1)
      {
      	if (b&1) x*=a,x%=mo;
      	a*=a;a%=mo;
	  }
	return x;
  } 
int main()
  {
    for (i=0;i<=1001;i++) c[i][0]=1;
    for (i=1;i<=1001;i++)
      for (j=1;j<=1001;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
    for (scanf("%lld",&T);T;T--)
      {
      	scanf("%lld",&n);
      	for (i=1;i<=n;i++) scanf("%lld",&a[i]);
      	sort(a+1,a+n+1);
		for(f[0]=i=1;i<=n;++i)
		  {
			f[i]=qsm(a[i],i);
			for(j=1;j


你可能感兴趣的:(noip模拟)