【NOIP模拟赛】Pickad 锄奸

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOI(全国青少年信息学奥林匹克竞模拟的测试数据是指用于评测参选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参选手的程序能否正确地解决问题。 在NOI模拟中,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟中起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞的保证,确保每个参选手有相同的机会和条件进行竞争。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值