传送门:HDU 3944
描述:
DP?
Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 128000/128000 K (Java/Others)
Total Submission(s): 3027 Accepted Submission(s): 950
Problem Description
Figure 1 shows the Yang Hui Triangle. We number the row from top to bottom 0,1,2,…and the column from left to right 0,1,2,….If using C(n,k) represents the number of row n, column k. The Yang Hui Triangle has a regular pattern as follows.
C(n,0)=C(n,n)=1 (n ≥ 0)
C(n,k)=C(n-1,k-1)+C(n-1,k) (0<k<n)
Write a program that calculates the minimum sum of numbers passed on a route that starts at the top and ends at row n, column k. Each step can go either straight down or diagonally down to the right like figure 2.
As the answer may be very large, you only need to output the answer mod p which is a prime.
Input
Input to the problem will consists of series of up to 100000 data sets. For each data there is a line contains three integers n, k(0<=k<=n<10^9) p(p<10^4 and p is a prime) . Input is terminated by end-of-file.
Output
For every test case, you should output "Case #C: " first, where C indicates the case number and starts at 1.Then output the minimum sum mod p.
Sample Input
1 1 2 4 2 7
Sample Output
Case #1: 0 Case #2: 5
Author
phyxnj@UESTC
Source
Recommend
题意:
告诉你在一个在杨辉三角中的点(第n行m列),问你从(0,0)点走到该点经过的点最少的权值和(只能向下走或斜着走)。同时对素数p取余
思路:
根据已知的那个点(n,m),如果 n/2 >= k,那么从已知点出发,可以一直往斜的方向走,直到边界,那么 权值和就为 C(n,m)+C(n-1,m-1)……. 然后由组合数的公式两两合并可以得到 C(n+1,k)+(n-k);如果n/2< k,那么就是一直往上走,权值和就为C(n,k)+C(n-1,k)+C(n-2,k)….. +C(k+1, k)+C(k,k)+k,将C(k,k)改成C(k+1,k+1),然后与前面的组合数合并等于C(n+1,k+1)+k。因为同样根据组合数的性质当k<=n/2,k=n-k。所以只剩下第二种情况。
同样用Lucas定理化简,但是样例有1e5组,非常大,但是p不大,不预处理会TLE。将每个数阶乘同10000以内的每个素数的取余都保存下来,到时候直接用。当一个数>=某个素数的时候,对这个素数取余肯定等于0,这相当于一个优化。
代码:
#include <bits/stdc++.h>
#define pr(x) cout << #x << "= " << x << " " ;
#define pl(x) cout << #x << "= " << x << endl;
#define ll __int64
#define mod 1000000007
using namespace std;
const int N = 10005;
bool prime[N];
int p[N],f[N][N],inv[N][N],cnt,pth[N];
void isprime(){//先声明
cnt=0;
memset(prime,1,sizeof(prime));
for(int i=2;i<N;i++){//埃式筛法
if(prime[i]){
p[++cnt]=i;//记录素数
pth[i]=cnt;//第几个素数
for(int j=i+i;j<N;j+=i)
prime[j]=0;
}
}
}
int pow_mod(int a,int b,int m){
int ans=1;
a%=m;
while(b){
if(b&1){
ans=ans*a%m;
b--;
}
b>>=1;
a=a*a%m;
}
return ans;
}
void init(){//预处理阶乘与逆元,先声明
for(int i=1;i<=cnt;i++){
f[i][0]=inv[i][0]=1;
for(int j=1;j<p[i];j++){
f[i][j]=(f[i][j-1]*j)%p[i]; //模第i个素数的所有阶乘
inv[i][j]=pow_mod(f[i][j],p[i]-2,p[i]); //模第i个素数的所有逆元
}
}
}
int C(int n,int m,int p){
if(m>n) return 0;
if(m==n) return 1;
int t=pth[p];
return f[t][n]*(inv[t][n-m]*inv[t][m]%p)%p;
}
int lucas(int n,int m,int p){
if(m==0) return 1;
return C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
}
int main(){
int n,k,P,kase=1;
isprime();
init();
while(~scanf("%d%d%d",&n,&k,&P)){
if(k<=n/2)k=n-k;
printf("Case #%d: %d\n", kase++,(k%P+lucas(n+1, k+1, P))%P);
}
return 0;
}

本文探讨了在杨辉三角中寻找从顶点到指定点的最短路径问题,并给出了解决方案。利用组合数学特性简化计算过程,通过预处理阶乘及逆元提升效率。

435

被折叠的 条评论
为什么被折叠?



