有 n n n种颜色的珠子每个珠子各有 a i a_i ai个,现在要用它们组成排列,但要求在排完第 i i i种颜色之前不能先排完第 i + 1 i+1 i+1个颜色,求排列的方案数
n ≤ 1 0 5 , ∑ a ≤ 5 × 1 0 5 n\leq 10^5,\sum a\leq5\times 10^5 n≤105,∑a≤5×105
首先我们很容易打出暴力的代码,然后就有40分了
#include<cstdio> #include<cctype> using namespace std;int n,ans,a[100001],sum; inline long long read() { char c;int d=1;long long f=0; while(c=getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48; while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48; return d*f; } inline void dfs(int dep,int *a) { for(register int i=n;i>=0;i--) if(a[i]==0&&a[i-1]>0) return; if(dep>sum) {ans++;return;} for(register int i=1;i<=n;i++) if(a[i]) { a[i]--; dfs(dep+1,a); a[i]++; } } signed main() { n=read(); for(register int i=1;i<=n;i++) a[i]=read(),sum+=a[i]; dfs(1,a); printf("%d\n",ans); }然后我们分析发现每次就是在剩余的空位种选择 a i a_i ai-1个,这样我们一个倒序循环+组合数计数就完事了
直接费马算逆元时间复杂度: O ( s u m l o g s u m + n ) O(sumlogsum+n) O(sumlogsum+n), O ( s u m ) O(sum) O(sum)推复杂度 O ( s u m + n ) O(sum+n) O(sum+n)(速度榜rk1)
