7.29 C幸运数字
?
问题描述每个人都会有幸运数字,有种幸运数字是这样定义的: 输入格式共一行,三个正整数 n、m 和 p,保证 p 是质数。 输出格式共一行,表示答案对 p 取模的值。 样例输入 14?3?23? 样例输出 115 样例输入 24?10?10000079? 样例输出 2715 提示前 20%的数据满足 n <= 18,m <= 10。 样例说明 样例 1 的 15 种方案如下: ? ? ? 分析: 这题有一个很显然的DP 考试的时候由于纠结B题太久 没有打前缀和优化? 掉了40分
20%搜索即可50%DP,f[i][j]表示以 j 结尾,长度为 i 的数字的个数。则 f[i][j]=sum{f[i-1][k]},k<=j,f[1][j]=1,复杂度 O(n^3)80%注意到前面求 f[i][j]时有求前缀和,那么用 g[i][j]表示 f[i][1]到 f[i][j]的和,则 dp 可以优化到O(nm)100%80 分的算法中,f[i][j]=g[i-1][j],也可以写成 g[i][j]-g[i][j-1]=g[i-1][j],即 g[i][j]=g[i-1][j]+g[i][j-1],这类似于一个杨辉三角形,并且发现边界 g[1][i]=i 恰好是杨辉三角形去掉最外层 1 的一边,因此可以使用组合数的方法进行直接计算 g[i][j]的值:g[i][j]=c(i,i+j-1);最终答案:ans=sum(g[i][m-1]),1<=i<=n根据 g[i][j]=g[i-1][j]+g[i][j-1]化简可以得到ans=g[n][m]=c(n,n+m-1)
?
至于g[i][[j] 为啥会得到C(i,i+j-1)? 我只能说靠经验
?
然后分享一波 lucas定理板子
C(N,M)=C(N%P,M%P)*lucas(N/P,M/P);
虽然说n+m<=p 用不到lucas
code:
// #include<bits/stdc++.h> using namespace std; #define ll long long ll n,m,p; ll ksm(ll a,ll b,ll c) { ll ans=1; while(b) { if(b&1) ans=ans%p*(a%p); b>>=1; a=(a*a)%c; } return ans%p; } ll c(int n,int m) { if(n<m) return 0; if(n==m) return 1; if(n-m<m) m=n-m; ll A=1,B=1; for(int i=0;i<m;i++) { A=(A%p)*(n-i)%p; B=(B%p)*(m-i)%p; } return ksm(B,p-2,p)*A; } ll lucas(int n,int m,int p) { if(m==0) return 1; else return lucas(n/p,m/p,p)%p*c(n%p,m%p)%p; } int main() { // freopen("lucknum.in","r",stdin); // freopen("lucknum.out","w",stdout); scanf("%lld%lld%lld",&n,&m,&p); printf("%lld",lucas(n+m-1,n,p)%p); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |