SRM 572 div2 1000

/*
注意dp的for循环,状态之间的重复计算
dp[i][j]表示i种不同的余数的和为j的方法树

  */
#include<stdio.h>
#include<string.h>

typedef long long  lld;
const int mod=1000000007;
lld dp[52][1300];
lld fac[52];

class DistinctRemainders{
public:
	lld Bin(lld a,lld b){
		lld ret=1;
		while(b){
			if(b&1)ret=ret*a%mod;
			b>>=1;
			a=a*a%mod;
		}
		return ret;
	}
	void init(int M){
		memset(fac,0,sizeof(fac));
		fac[0]=1;
		for(int i=1;i<=M;i++)
			fac[i]=fac[i-1]*i%mod;
	}
	lld Kao(lld x,lld y){
		lld ret=1;
		for(lld i=1;i<=y;i++){
			ret=ret*x%mod;
			x--;
		}
		return ret;
	}
	lld Gao(lld x,lld y){
		return Kao(y,x)*Bin(Kao(x,x),mod-2)%mod;
	}
	int howMany(lld N, int M){
		int i,j,k;
		init(M);
		memset(dp,0,sizeof(dp));
		dp[0][0]=1;
		for(i=0;i<M;i++){
			for(j=M;j>0;j--){
				for(k=M*M/2;k>=i;k--){
					if(!dp[j-1][k-i])continue;
					dp[j][k]=(dp[j-1][k-i]+dp[j][k])%mod;
				//	printf("dp[%d][%d]=%lld \n",i,j,dp[i][j]);
				}
			}
		}
		lld ans=0;
		for(i=1;i<=M;i++){
			for(j=0;j<=M*M/2;j++){
				if(!dp[i][j])continue;
				if(j>N || (N-j)%M!=0)continue;
				ans=(ans+(dp[i][j]*fac[i]%mod)*Gao(i-1,(N-j)/M%mod+i-1))%mod;
				printf("i==%d j==%d %lld \n",i,j,ans);
			}
		}
		return (int)ans;
	}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值