1118
链接 : http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1118
普通的一个2位的DP 直接跑就行了
#include<bits/stdc++.h>
using namespace std;
int dp[1005][1005];
const int mod=1e9+7;
int main()
{
int m,n;
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
dp[i][1]=1;
for(int i=1;i<=n;i++)
dp[1][i]=1;
for(int i=2;i<=m;i++)
{
for(int j=2;j<=n;j++)
dp[i][j]=((dp[i-1][j]+dp[i][j-1]))%mod;
}
printf("%d\n",dp[m][n]);
return 0;
}
1119
题目连接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1119
题意一样 就是数据变大了,n^m肯定不行 所以用到了组合数打表+费马小定理 n,m范围小 mod范围大
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int P = 1000000007;
LL f[2000005], v[2000005];
LL rp(LL now, int k)
{
LL will = 1;
for (; k; k >>= 1, now *= now, now %= P)
{
if (k & 1) will *= now, will %= P;
}
return will;
}
LL C(int n, int m)
{
if(n < m) return 0;
return f[n] * rp(f[m], P - 2) % P * rp(f[n - m], P - 2) % P;
}
void init()
{
f[0] = 1; v[0] = 1;
for (int i = 1; i <= 2000005; i++) //1e6以内的组合数
{
f[i] = f[i - 1] * i % P;
}
}
int main()
{
init();
int n, m;
scanf("%d %d", &n, &m);
printf("%lld\n", C(m+n-2, n-1));
}
1120
题目连接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1120
题意差不多,就是n和m的范围变得更大 但是取模的数据变小。所以考虑用模 用lucas定理(取模的一定是素数)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int NICO = 10010;
const int MOD = 10007;
LL f[NICO];
LL Pow(LL a, LL n)
{
LL ret = 1;
while(n)
{
if(n & 1)
{
ret = (ret * a);
ret %= MOD;
}
a = a * a % MOD;
n >>= 1;
}
return ret;
}
LL Lucas(LL a,LL k)
{
LL res = 1;
while(a && k)
{
LL a1 = a % MOD;
LL b1 = k % MOD;
if(a1 < b1) return 0;
res = res*f[a1]*Pow(f[b1]*f[a1-b1]%MOD,MOD-2)%MOD;
a /= MOD;
k /= MOD;
}
return res;
}
void init()
{
f[0] = 1;
for(int i=1;i<=MOD;i++)
{
f[i] = f[i-1]*i%MOD;
}
}
LL T, n;
int main()
{
init();
int n;
scanf("%d",&n);
n--;
cout << ((Lucas(n<<1,n)+MOD-Lucas(n<<1,n-1))%MOD*2)%MOD << endl;
}
nefu 628
题目连接 : http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=628
题目和上边的机器人的V3差不多 但是就是mod的数不一定了 可能不是素数 因此就不能那样求了,
就变成了求n!/(m!*(n-m)!) 上边和下边都可以写成素数的乘积 n和m的范围为1e5因此打素数表然后暴力求素数的次方差然后快速幂求解。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
bool prime[maxn];
int p[maxn];
int cnt;
int mod;
void isprime()
{
cnt=0;
memset(prime,true,sizeof(prime));
for(int i=2;i<maxn;i++)
{
if(prime[i])
{
p[cnt++] = i;
for(int j=i+i;j<maxn;j+=i)
prime[j] = false;
}
}
}
ll quick_mod(ll a,ll b,ll m)
{
ll ans=1;
while(b)
{
if(b&1)
{
ans=ans*a%m;
}
b>>=1;
a=a*a%m;
}
return ans;
}
ll fun(ll n,ll m)///计算n!中m这个素因子的个数
{
ll ans=0;
while(n)
{
ans+=n/m;
n=n/m;
}
return ans;
}
ll solve(ll n,ll m,ll pp)
{
n=n+m-2;
m=m-1;
ll ans=1;
for(int i=0;i<cnt&&p[i]<=n;i++)
{
ll x=fun(n,p[i]);
ll y=fun(n-m,p[i]);
ll z=fun(m,p[i]);
ll xx=x-y-z;
ans=ans*quick_mod(p[i],xx,pp)%pp;
}
return ans;
}
int main()
{
isprime();
int t;
scanf("%d",&t);
while(t--)
{
ll n,m,pp;
scanf("%lld%lld%lld",&n,&m,&pp);
printf("%lld\n",solve(n,m,pp));
}
return 0;
}