码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ5339:[TJOI2018]教科书般的亵渎——题解

时间:2018-05-21 14:31:04      阅读:303      评论:0      收藏:0      [点我收藏+]

标签:相同   递推   log   logs   inline   ret   ref   block   for   

https://www.lydsy.com/JudgeOnline/problem.php?id=5339

https://www.luogu.org/problemnew/show/P4593

小豆喜欢玩游戏, 现在他在玩一个游戏遇到这样的场面,每个怪的血量为ai,且每个怪物血量均不相同, 小豆手里有无限张“亵渎”。亵渎的效果是对所有的怪造成1点伤害,如果有怪死亡,则再次施放该法术。我们认为血量为0时怪物死亡。小豆使用一张“亵渎”会获得一定的分数,分数计算如下,在使用一张“亵渎”之后,每一个被亵渎造成伤害的怪会产生x^k,其中x是造成伤害前怪的血量为x和需要杀死所有怪物所需的“亵渎”的张数k。

参考:https://www.luogu.org/blog/user44829/solution-p4593 ,你可以在这个博客里面找到各种各样的本题做法。

题意很乱,但是整理整理后发现实际上你只需要知道如何求出\(S(n,k)=\sum_{i=1}^na_i^k\)即可。

直接给公式\(S(n,k)=\frac{1}{k+1}\sum_{i=1}^{k+1}C^i_{k+1}B_{k+1-i}(n+1)^i\)

组合数递推:

\(C^m_n=C^m_{n-1}+C^{m-1}_{n-1}\)

伯努利数递推:

\(B_n=[m=0]-\sum_{k=0}^{m-1}C_m^k\frac{B_k}{m-k+1}\)

\(m=n-1\)

#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll p=1e9+7;
const int N=65;
inline ll read(){
    ll X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
ll n,a[N],inv[N],c[N][N],b[N];
int m;
ll qpow(ll x,ll y){
    ll res=1;
    while(y){
    if(y&1)res=res*x%p;
    x=x*x%p;y>>=1;
    }
    return res;
}
ll f(ll x,ll y){
    ll res=0;
    for(int i=1;i<=y+1;i++){
    res=(res+c[y+1][i]*b[y+1-i]%p*qpow(x+1,i)%p)%p;
    }
    res=res*inv[y+1]%p;
    return res;
}
inline void init(){
    for(int i=1;i<N;i++)inv[i]=qpow(i,p-2);
    for(int i=0;i<N;i++){
    c[i][0]=1;
    for(int j=1;j<=i;j++){
        c[i][j]=(c[i-1][j]+c[i-1][j-1])%p;
    }
    }
    b[0]=1;
    for(int i=1;i<N;i++){
    b[i]=0;
    for(int j=0;j<=i-1;j++)b[i]=(b[i]+c[i+1][j]*b[j]%p)%p;
    b[i]=(p-b[i])*inv[i+1]%p;
    }
}
int main(){
    init();
    int t=read();
    while(t--){
    n=read(),m=read();
    for(int i=1;i<=m;i++)a[i]=read();
    a[++m]=++n;
    sort(a+1,a+m+1);
    ll ans=0;
    for(int i=1;i<=m;i++){
        for(int j=i;j<=m;j++){
        ans=(ans+f(a[j]-1,m)-f(a[j-1],m)+p)%p;
        }
        for(int j=i+1;j<=m;j++)a[j]-=a[i];
        a[i]=0;
    }
    printf("%lld\n",ans);
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

BZOJ5339:[TJOI2018]教科书般的亵渎——题解

标签:相同   递推   log   logs   inline   ret   ref   block   for   

原文地址:https://www.cnblogs.com/luyouqi233/p/9066431.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!