3504. 【NOIP2013模拟11.4B组】运算符(calc)

64 篇文章 0 订阅
29 篇文章 13 订阅

Description

鸡腿想到了一个很高(sha)明(bi)的运算符,那就是’!’,没错就是感叹号。他给了如下的定义:

1、n!k = n!(k-1) * (n-1)!k (n> 0 and k > 0)

2、n!k = 1 (n = 0)

3、n!k = n (k = 0)

现在鸡腿告诉你n和k你能告诉他n!k的不同约数个数有多少个吗?只要对1,000,000,009取模就可以了哦!

Input

一行,输入两个正整数n,k。

Output

一行,输出一个整数表示答案。

Sample Input

输入1:

3 1

输入2:

100 2

Sample Output

输出1:

4

输出2:

321266186

Data Constraint

对于30%的数据0 <n ≤ 10, 0 <k ≤ 10;

对于100%的数据0 <n ≤ 1000, 0 <k ≤ 100。

Solution

题意是定义n!k=(n-1)!k*n!(k-1),当k=0时n!k=n,当n=0时n!k=1,求n!k的约数的个数。
容易想到dp。
把整个过程看做一个矩阵。
设f[i][j][k]表示做到第i行第j列这个数的第k个质因子有多少个。
f[i][j][k]=f[i-1][j][k]+f[i][j-1][k]。
最后答案即为i=1~k(f[n][m][i]+1)的乘积。


但是我们发现如果n开大一些这样的算法就通不过了。
我们可以想因为只有(i,0)的点才会对答案有贡献,因此我们可以算出从(i,0)推到(n,m)的方案数,再用1~n的质因子直接累加即可。
那么(i,0)推到(n,m)的方案数是多少呢?
因为(i,0)只能由(i,1)推来所以我们就要计算(i,1)到(n,m)的方案。
同样抽象成一个二维平面,我们每次从(i,1)这个点出发,走到(n,m)的方案数,实际上就是C(n-i+m-1,n-i)。
至此我们可以求出每个质因子的倍数,此题得到解答。

第三种解法:

Code1

#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define N 102
#define M 1000000009
using namespace std;
ll n,m,p[180],bz[1010],f[2][N][170],id[1010],o,ans=1;
I main(){
	freopen("calc.in","r",stdin);
	freopen("calc.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	bz[1]=1;
	F(i,2,n){
		if(!bz[i]){
			p[++p[0]]=i;
			id[i]=p[0];
			F(j,2,n/i) bz[j*i]=1;
		}
	}
	F(i,1,n){
		o=1-o;
		F(k,1,p[0]) f[o][0][k]=0;
		I x=i;
		F(j,1,p[0]){
			if(p[j]>x) break;
			if(x%p[j]==0){
				while(x%p[j]==0){
					x/=p[j];
					f[o][0][id[p[j]]]++;
					f[o][0][id[p[j]]]%=M;
				}
			}
		}
		if(!bz[x]){
			f[o][0][id[x]]++;
			f[o][0][id[x]]%=M;
		}
		F(j,1,m){
			F(k,1,p[0]) f[o][j][k]=0;
			F(k,1,p[0]){
				f[o][j][k]=(f[o][j][k]+f[1-o][j][k])%M;
				f[o][j][k]=(f[o][j][k]+f[o][j-1][k])%M;
			}
		}
	}
	F(i,1,p[0]) ans=(ans*(f[o][m][i]+1)%M)%M;
	printf("%lld\n",ans);
	return 0;
}

Code2

#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define F(i,a,b) for(ll i=a;i<=b;i++)
#define Fd(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define N 1002
#define M 1000000009
using namespace std;
ll n,m,ans=1,p[200],bz[N],f[N*2],inv[N*2],c[200],t[200];
ll ksm(ll x,ll k){
	if(k==1) return x;
	ll s=ksm(x,k/2);s=(s*s)%M;
	if(k&1) return (s*x)%M;
	return s;
}
ll C(ll x,ll y){
	return (((f[x]*inv[y])%M)*inv[x-y])%M;
}
I main(){
	freopen("calc.in","r",stdin);
	freopen("calc.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	f[0]=1;
	F(i,1,n+m) f[i]=(f[i-1]*i)%M;
	inv[n+m]=ksm(f[n+m],M-2);
	Fd(i,n+m-1,0) inv[i]=(inv[i+1]*(i+1))%M;
	F(i,2,n){
		if(!bz[i]) p[++p[0]]=i;
		F(j,1,p[0]){
			if(p[j]*i>n) break;
			bz[p[j]*i]=1;
			if(i%p[j]==0) break;
		}
	}
	F(i,1,n){
		ll x=i,st=C(n-i+m-1,m-1);
		mem(c,0);
		F(j,1,p[0]){
			if(x%p[j]==0){
				while(x%p[j]==0){
					c[j]=(c[j]+st)%M;
					x/=p[j];
				}
				if(x==1) break;
			}
		}
		F(j,1,p[0]) t[j]=(t[j]+c[j])%M;
	}
	F(i,1,p[0]) ans=(ans*(t[i]+1))%M;
	printf("%lld\n",ans);
	return 0;
}


作者:zsjzliziyang 
QQ:1634151125 
转载及修改请注明 
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/99697121

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值