Mysterious For

一、题目

点此看题

题目描述

m m m个循环,分为两类,第一类循环从 [ 1 , n ] [1,n] [1,n],第二类从上一个变量开始循环到 n n n,有 k k k个一类循环,问最终会循环多少次,答案模一个数 364875103 364875103 364875103

二、解法

可以把原问题变成 k k k个子问题,然后利用乘法原理即可。

考虑一个循环个数为 t t t的子问题,可以转化为 t t t个不同的小球, n n n的相同的盒子,盒子可以为空,所以我们先把每个盒子放一个球,然后用插板法可以算出方案数是 C ( n + t − 1 , t ) C(n+t-1,t) C(n+t1,t)

然后给出的这个模数可以分解成一个质数 97 97 97和另一个质数, 97 97 97 l u c a s lucas lucas处理即可,另一个较大的质数直接预处理阶乘,最后用普通 c t r ctr ctr合并即可。

#include <cstdio>
#define M 1100005
#define int long long
const int M1 = 97;
const int M2 = 364875103/97;
const int MOD = 364875103;
int read()
{
    int x=0,flag=1;char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int T,n,m,k,r1,r2,ans,a[20],fac[M],inv[M],f1[100];
void init()
{
	fac[0]=inv[0]=inv[1]=f1[0]=1;
	for(int i=2;i<M;i++) inv[i]=inv[M2%i]*(M2-M2/i)%M2;
	for(int i=1;i<M;i++) inv[i]=inv[i]*inv[i-1]%M2;
	for(int i=1;i<M;i++) fac[i]=fac[i-1]*i%M2;
	for(int i=1;i<100;i++) f1[i]=f1[i-1]*i%M1;
}
int qkpow(int a,int b,int p)
{
	int r=1;
	while(b>0)
	{
		if(b&1) r=r*a%p;
		a=a*a%p;
		b>>=1;
	}
	return r;
}
int C(int n,int m)
{
	if(n<m) return 0;
	return f1[n]*qkpow(f1[m]*f1[n-m]%M1,M1-2,M1)%M1;
}
int lucas(int n,int m)
{
	if(m==0) return 1;
	return lucas(n/M1,m/M1)*C(n%M1,m%M1)%M1;
}
signed main()
{
	init();
	T=read();
	for(int Cs=1;Cs<=T;Cs++)
	{
		n=read();m=read();k=read();
		for(int i=1;i<=k;i++)
			a[i]=read();
		a[++k]=m;r1=r2=1;
		for(int i=2;i<=k;i++)
		{
			int t=a[i]-a[i-1];
			r1=r1*lucas(n+t-1,t)%M1;
			r2=r2*fac[n+t-1]%M2*inv[t]%M2*inv[n-1]%M2;
		}
		ans=(r1*M2*qkpow(M2,M1-2,MOD)+r2*M1*qkpow(M1,M2-2,MOD))%MOD;
		printf("Case #%lld: %lld\n",Cs,ans);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值