Description
有 n−m n − m 只怪物,血量分别为 1 1 ~中去掉 m m 个数字,一次亵渎卡的效果是:首先所有怪物血量减一,如果存在怪物血量清零则所有怪物血量继续减一,使用该亵渎卡后,每只怪物对分数的贡献为 xk x k ,其中 x x 是该怪物在使用该卡之前的血量,为杀死所有怪物所需的亵渎卡数量,问杀死所有怪物所得分数和
Input
第一行一整数 T T 表示用例组数,每组用例首先输入两整数,之后输入 m m 个整数
(1≤T≤10,1≤n≤1013,1≤m≤50,1≤ai≤n,ai≠aj) ( 1 ≤ T ≤ 10 , 1 ≤ n ≤ 10 13 , 1 ≤ m ≤ 50 , 1 ≤ a i ≤ n , a i ≠ a j )
Output
输出得分,结果模 109+7 10 9 + 7
Sample Input
2
10 1
5
4 2
1
2
Sample Output
415
135
Solution
假设 a a 序列升序且,那么第一张亵渎卡的效果会杀掉 [1,a1−1] [ 1 , a 1 − 1 ] 的所有怪物,而之后的怪物血量变成 [1,a2−a1−1],[a2−a1+1,a3−a1−1],...,[am−a1+1,n−a1] [ 1 , a 2 − a 1 − 1 ] , [ a 2 − a 1 + 1 , a 3 − a 1 − 1 ] , . . . , [ a m − a 1 + 1 , n − a 1 ] ,显然每使用一次亵渎就会消去一个区间,故 k=m+1 k = m + 1 ,且第 i i 次使用亵渎得分为,故问题转化为求自然数幂和,用伯努利数或第二类斯特林数均可求出幂和,此处说一下如何用第二类斯特林数求解,记 Sk(n)=∑i=1nik S k ( n ) = ∑ i = 1 n i k
考虑恒等式
nk=∑i=1kAin⋅S(k,i)
n
k
=
∑
i
=
1
k
A
n
i
⋅
S
(
k
,
i
)
,我们有
注意到
故有
连续 i+1 i + 1 个数字相乘必可被 i+1 i + 1 整除,故对任意模数均可 O(k) O ( k ) 计算 Ci+1n+1i+1 C n + 1 i + 1 i + 1 ,预处理第二类斯特林数和单次查询时间复杂度均为 O(k2) O ( k 2 )
Code
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 105
#define mod 1000000007
int mul(int x,int y)
{
ll z=1ll*x*y;
return z-z/mod*mod;
}
int add(int x,int y)
{
x+=y;
if(x>=mod)x-=mod;
return x;
}
int Pow(int x,int y)
{
int ans=1;
while(y)
{
if(y&1)ans=mul(ans,x);
x=mul(x,x);
y>>=1;
}
return ans;
}
int S[maxn][maxn];
void init(int n=52)
{
S[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=i;j++)
S[i][j]=add(S[i-1][j-1],mul(j,S[i-1][j]));
}
int Solve(ll n,int k)
{
int ans=0;
for(int i=1;i<=k;i++)
{
int res=S[k][i];
for(ll j=n+1-i;j<=n+1;j++)
if(j%(i+1)==0)res=mul(res,j/(i+1)%mod);
else res=mul(res,j%mod);
ans=add(ans,res);
}
return ans;
}
int T,m;
ll n,a[maxn];
int main()
{
init();
scanf("%d",&T);
while(T--)
{
scanf("%lld%d",&n,&m);
for(int i=1;i<=m;i++)scanf("%lld",&a[i]);
sort(a+1,a+m+1);
int ans=0;
for(int i=1;i<=m+1;i++)
{
ans=add(ans,Solve(n-a[i-1],m+1));
for(int j=i;j<=m;j++)ans=add(ans,mod-Pow((a[j]-a[i-1])%mod,m+1));
}
printf("%d\n",ans);
}
return 0;
}