【2025.10.14NOIP】WYF的盒子

题目描述

WYF有一个精致的k维立方体盒子(2维为正方形,3维为正方体,以此类推)。这个盒子的边长为n,里面有一个边长为n-1的盒子,边长为n-1的盒子里面还有一个边长为n-2的盒子……最里面的盒子边长为m。现在WYF想知道这n-m+1个盒子的k维体积和模p的余数。

输入

输入共一行包含4个正整数k, n, m, p。

输出

输出共一行包含1个正整数,表示n-m+1个盒子的k维体积之和模p的余数。

样例输入 复制
输入1:
4 2 2 97

输入2:
1 100 1 10007
 
样例输出 复制
输出1:
16
【样例说明】
边长为2的4维立方体的4维体积为16。

输出2
5050
数据范围限制

思路

考虑n-m<=5000特判,否则利用伯努利数:

        b_i=-\frac{1}{i+1}\sum_{j=0}^{i-1}\binom{i+1}{j}b_j

        \sum_{i=1}^{n}i^k=\frac{1}{k+1}\sum_{j=0}^{k}\binom{k+1}{j}b_jn^{k-j+1}

O(n^2)出解。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long k,n,m,p,lk=0,f[5150][5150],b[5150],nn[5150],jx[5150],jx2[5150];
long long pow2(long long a1,long long b1,long long m1){
    long long kk1=1;
    a1%=p;
    while(b1>=1){
        if(b1%2==1){
            kk1=kk1*a1%p;
        }
        b1/=2;
        a1=a1*a1%p;
    }
    if(a1==0){
    	kk1=0;
	}
    return kk1; 
}
long long bnl2(long long a1,long long b1){
	long long op=0;
	for(int i=0;i<=b1;i++){
		op=(op+pow2(a1,b1-i,p)*b[i]%p*f[b1][i]%p)%p;
	}
	op=(op+p)%p;
	//cout<<op<<endl;
	return op;
}
long long bnl(long long a1,long long b1){
	long long op=0;
	for(int i=0;i<=b1;i++){
		op=(op+pow2(a1,b1+1-i,p)*b[i]%p*f[b1+1][i]%p)%p;
		//cout<<pow2(a1,b1+1-i,p)<<" "<<b[i]<<" "<<f[b1+1][i]<<endl;
	}
	op=(op+p)%p;
	op=nn[b1+1]*op%p;
	//cout<<nn[0]<<endl;
	return op;
}
int main(){
	cin>>k>>n>>m>>p;
	if(n-m<=6000){
		lk=0;
		for(int i=m;i<=n;i++){
			lk=(lk+pow2(i,k,p))%p;
		}
		cout<<lk<<endl;
	}
	else{
		for(int i=0;i<=5000;i++){
			f[i][0]=1;
		}
		for(int i=0;i<=5000;i++){
			f[i][i]=1;
		}
		for(int i=0;i<=5000;i++){
			for(int j=1;j<=i;j++){
				f[i][j]=(f[i-1][j-1]+f[i-1][j])%p;
			}
		}	
		for(int i=1;i<=5000;i++){
			nn[i]=pow2(i,p-2,p);
		}
		b[0]=1;
		for(int i=1;i<=5000;i++){
			for(int j=0;j<=i-1;j++){
				b[i]=(b[i]+b[j]*f[i+1][j])%p;
			}
			b[i]=(-nn[i+1]*b[i]%p)%p;
			//cout<<b[i]<<endl;
		}
		b[1]=-b[1];
		cout<<(bnl(n,k)-bnl(m-1,k)+p)%p<<endl;
	}
	return 0;
}

posted @ 2025-10-14 10:47  bz02_2023f2  阅读(9)  评论(0)    收藏  举报  来源