zoukankan      html  css  js  c++  java
  • BZOJ5339:[TJOI2018]教科书般的亵渎——题解

    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^kfrac{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
    ",ans);
        }
        return 0;
    }
    

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

    +本文作者:luyouqi233。               +

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

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

  • 相关阅读:
    面向接口程序设计思想实践
    Block Chain Learning Notes
    ECMAScript 6.0
    Etcd Learning Notes
    Travis CI Build Continuous Integration
    Markdown Learning Notes
    SPRING MICROSERVICES IN ACTION
    Java Interview Questions Summary
    Node.js Learning Notes
    Apache Thrift Learning Notes
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9066431.html
Copyright © 2011-2022 走看看