题意:
在炉石传说中有这样的一个场面:n个随从,血量为1~n,现在去除m个随从,然后开始释放“亵渎”。每使用一张“亵渎”会获得一定的分数,分数计算如下:在使用一张“亵渎”之后,每一个被亵渎造成伤害的怪会产生 xk x k 的分数,其中x是造成伤害前怪的血量,k是需要杀死所有怪物所需的“亵渎”的张数。
n≤1013m≤50 n ≤ 10 13 m ≤ 50
Solution:
可以发现这是若干个形如 Sum(n,k)=∑ni=1ik S u m ( n , k ) = ∑ i = 1 n i k 的式子组成的
这就是经典的自然数幂和问题了
可以用累加法:
首先有一个式子: (n+1)k−nk=∑ki=1Cik∗nk−i ( n + 1 ) k − n k = ∑ i = 1 k C k i ∗ n k − i
左边组合意义是k个球涂n+1种颜色的方案数和k个球涂n种颜色的方案数
右边组合意义是在k个球选一些球涂第n+1种颜色,其他球随便涂的方案数
然后我们可以通过上面的式子列出若干式子:
(n+1)k−nk=∑ki=1Cik∗nk−i ( n + 1 ) k − n k = ∑ i = 1 k C k i ∗ n k − i
nk−(n−1)k=∑ki=1Cik∗(n−1)k−i n k − ( n − 1 ) k = ∑ i = 1 k C k i ∗ ( n − 1 ) k − i
(n−1)k−(n−2)k=∑ki=1Cik∗(n−2)k−i ( n − 1 ) k − ( n − 2 ) k = ∑ i = 1 k C k i ∗ ( n − 2 ) k − i
... . . .
2k−1k=∑ki=1Cik∗1k−i 2 k − 1 k = ∑ i = 1 k C k i ∗ 1 k − i
全都加起来可以得到: (n+1)k−1=∑ki=1Cik∗Sum(n,k−i) ( n + 1 ) k − 1 = ∑ i = 1 k C k i ∗ S u m ( n , k − i )
即 (n+1)k+1−1=∑k+1i=1Cik+1∗Sum(n,k−i+1) ( n + 1 ) k + 1 − 1 = ∑ i = 1 k + 1 C k + 1 i ∗ S u m ( n , k − i + 1 )
(n+1)k+1−1=∑k+1i=2Cik+1∗Sum(n,k−i+1)+(k+1)∗Sum(n,k) ( n + 1 ) k + 1 − 1 = ∑ i = 2 k + 1 C k + 1 i ∗ S u m ( n , k − i + 1 ) + ( k + 1 ) ∗ S u m ( n , k )
Sum(n,k)=(n+1)k+1−1−∑k−1i=0Cik+1∗Sum(n,i)k+1 S u m ( n , k ) = ( n + 1 ) k + 1 − 1 − ∑ i = 0 k − 1 C k + 1 i ∗ S u m ( n , i ) k + 1
这样我们就可以 O(k2) O ( k 2 ) 的递推了,临界点是 Sum(n,0)=n S u m ( n , 0 ) = n 记忆化搜索即可
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int mod=1e9+7;
long long n,nw,a[55];
int T,mi,k,ans[55],c[55][55];
int fast_pow(int x,int a)
{
int ans=1;
for (;a;x=1ll*x*x%mod,a>>=1)
if (a&1) ans=1ll*ans*x%mod;
return ans;
}
int S(int k)
{
if (k==0) return nw%mod;
if (ans[k]) return ans[k];
int Ans=fast_pow((nw+1)%mod,k+1);//cout<<Ans<<endl;
int jian=1;
for (int i=0;i<=k-1;i++) jian=(jian+1ll*c[i][k+1]*S(i))%mod;
Ans=(Ans+mod-jian)%mod;
Ans=(1ll*Ans*fast_pow(k+1,mod-2))%mod;
ans[k]=Ans;
return Ans;
}
int main()
{
c[0][0]=1;
for (int i=1;i<=52;i++)
{
c[0][i]=1;
for (int j=1;j<=i;j++) c[j][i]=(1ll*c[j][i-1]+c[j-1][i-1])%mod;
}
scanf("%d",&T);
while (T--)
{
scanf("%lld%d",&n,&k);
for (int i=1;i<=k;i++) scanf("%lld",&a[i]);
sort(a+1,a+1+k);
mi=k+1;
int tot=0;
nw=n;
for (int i=1;i<=k;i++)
{
memset(ans,0,sizeof(ans));
tot=(1ll*tot+S(mi))%mod;
for (int j=i;j<=k;j++) tot=(1ll*tot-fast_pow((a[j]-n+nw)%mod,mi)+mod)%mod;
//cout<<tot<<endl;
nw-=a[i]-a[i-1];
}
memset(ans,0,sizeof(ans));//cout<<nw<<endl;
tot=(1ll*tot+S(mi))%mod;
printf("%d\n",tot);
}
}