题解 luoguP4593 【[TJOI2018]教科书般的亵渎】

传送门

先算出所需亵渎个数 k k k,观察就可以发现 k = m + 1 k=m+1 k=m+1,有一个小细节,如果从 n n n开始有一段连续的空位,应该把它去掉,因为不会需要多余的亵渎。

我们计算每一次亵渎的贡献,第一次亵渎我们认为是在 0 0 0位置。显然第一次的贡献是 i = 1 n i k \sum\limits_{i=1}^{n}i^k i=1nik - 空位的贡献。

之后我们考虑在一个空位上使用亵渎,设空位为 p p p,那么有贡献的区间为 p + 1 n p+1 \sim n p+1n。贡献为 i = 1 n p i k \sum\limits_{i=1}^{n-p}i^k i=1npik

最后我们减去空位多算的贡献即可。

考虑计算 i = 1 n i k \sum\limits_{i=1}^{n}i^k i=1nik,可利用拉格朗日插值,参考这里

C o d e <mtext>   </mtext> B e l o w : Code\ Below: Code Below:

#include<bits/stdc++.h>
#define ts cout<<"ok"<<endl
#define int long long
#define hh puts("")
#define mo 1000000007
using namespace std;
int n,m,a[55],k,f[55],pre[55],suf[55],fac[55],ans;
map<int,int> ma;
inline int read(){
    int ret=0,ff=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') ff=-ff;ch=getchar();}
    while(isdigit(ch)){ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
    return ret*ff;
}
void write(int x){
    if(x>9) write(x/10);
    putchar(x%10+48);
}
inline int ksm(int x,int y){
    int res=1;
    while(y){
        if(y&1) res=res*x%mo;
        y>>=1;
        x=x*x%mo;
    }
    return res;
}
inline int calc(int p){
    if(p<=k+2) return f[p];
    int res=0;
    pre[0]=1;
    for(int i=1;i<=k+2;i++) pre[i]=pre[i-1]*(p-i)%mo;
    suf[k+3]=1;
    for(int i=k+2;i>=1;i--) suf[i]=suf[i+1]*(p-i)%mo;
    for(int i=1;i<=k+2;i++){
        int x=pre[i-1]*suf[i+1]%mo;
        int fu=((k+2-i)&1)?-1:1;
        int y=fac[i-1]*fac[k+2-i]*fu%mo;
        res=(res+f[i]*x%mo*ksm(y,mo-2)%mo)%mo;
    }
    return (res+mo)%mo;
}
signed main(){
    fac[0]=1;
    for(int i=1;i<=52;i++) fac[i]=fac[i-1]*i%mo;
    int T=read();
    while(T--){
        n=read(),m=read();
        k=m+1;
        ma.clear();
        for(int i=1;i<=m;i++) a[i]=read(),ma[a[i]]=1;
        sort(a+1,a+m+1);
        while(ma[n]) n--,k--,m--;
        for(int i=1;i<=k+2;i++) f[i]=(f[i-1]+ksm(i,k))%mo;
        ans=calc(n);
        for(int i=1;i<=m;i++) ans=(ans-ksm(a[i],k))%mo;
        for(int i=1;i<=m;i++) ans=(ans+calc(n-a[i]))%mo;
        for(int i=1;i<=m;i++)
            for(int j=i-1;j>=1;j--)
                ans=(ans-ksm(a[i]-a[j],k))%mo;
        write((ans+mo)%mo),hh;
    }
    return 0;
}
全部评论

相关推荐

大方的大熊猫准备进厂:1.教育背景:你希望从事什么专业的工作你的主修课就是什么;成绩优秀是你应该做的,没什么可描述的,成绩不优秀也许人家在大学忙着创业呢?(成绩优秀不一定是好事,只能说明多元化的大学你上成了高中,没有真正上明白大学,反而体现了你死板,不爱社交,没有别的突出能力) 2.实践经历:你想表达的意思没有说清楚。你是说你会个性化服务,还是你有实习经历。如果没有带来,经济收益,表彰,更好的发展前景,那你还不如说说提升了自己哪些技能。你说有人给你送锦旗我都能明白你优秀,但是你说你会xxxx,你说这话谁信,证据呢。 3.入伍经历:你描述的就是你的工作职责或者你应该做的,并没有体现出来你把这个事情做好了,而且入伍经历并不能证明你能干好你要应聘的工作,不如只写经历其余所有内容都不写。 4.荣誉技能:重点突出一下,但不要过多描述,这些荣誉的含金量懂得都懂。 重点:你要应聘什么工作(具体岗位,实习生不具体),你的期望薪资
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务