牛客补题:链接:登录—专业IT笔试面试备考平台_牛客网
我有精兵组阵,兵阵可看做一个 n×m 的矩阵,现在从左上角 (1,1) 派遣出通讯兵 去 (n,m) 传令,通讯兵每一步仅能向右走或者向下走,求会有几种不同的路线,答案对 998244353 取模。
n<= 1000000,m,T <= 5000
这道题很经典啊,寒假集训学的dp,奈何当时看了数据范围,dp肯定爆。
正确题解是数学组合数,要走到(n,m)坐标中,右走m步,下走n步。而不同的路径可以看作是从n+m步中选择n步向右走的方案数,即为组合数C(n+m, n)。
#include<bits/stdc++.h> #define int long long using namespace std; const int Mod=998244353; const int N=2e6; vector<int>g(N,0); int ksm(int a,int b){//a^b int ans=1; while(b){ if(b&1) ans=ans*a%Mod; a=a*a%Mod; b>>=1; } return ans; } int C(int x,int y){//组合数:x中取y if(x==0||y==0) return 1; return g[x]*ksm((g[x-y]*g[y])%Mod,Mod-2)%Mod;//费马小定理求逆元 }//(g[x-y]*g[y])%Mod 这里不取Mod,精度会WA void solve(){ int n,m; cin>>n>>m; n--,m--; cout<<C(n+m,m)<<'\n'; } signed main() { ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); g[0]=1; for(int i=1;i<=N;i++){//预处理阶乘 g[i]=(g[i-1]*i)%Mod; } int t; cin>>t; while(t--){ solve(); } return 0; }
预处理阶乘。组合数公式:C(y,x)=!x / !y*!(x-y)
除数取模,得用逆元啊!费马小定理求逆元,转换为乘法,用快速幂。时间复杂度转为O(nlogn)级别。
细节:在传入快速幂,(g[x-y]*g[y])%Mod 这里不取Mod,精度会WA。
总结:思路最重要,就是组合数求方案,不管是再高深的算法,快速幂,逆元,都是用来实现你思路的工具罢了。学思路!!!