Luogu3223 [HNOI2012]排隊(排列組合)題解
阿新 • • 發佈:2020-11-16
數學題
排列組合+高精度
前置芝士
思路
考慮容斥,老師不相鄰的方案數\(=\)不考慮老師特殊要求的方案數\(-\)保證老師相鄰的方案數
- 不考慮老師限制,即老師與男生相同,則方案數為:\(A(n+3,m)\times A(n+2,n+2)\)
- 保證老師相鄰,即把兩個老師捆在一起,看做一個男生,則方案數為:\(A(n+2,m)\times A(n+1,n+1)\times A(2,2)\)
由於\(n\)和\(m\)都很小,可以直接高精度暴力計算排列。
注意:壓位高精記得要控制輸出位數!
程式碼
#include <cstdio> #define LL long long using namespace std; const int maxn = 1e4 + 10; const LL p = 10000000000ll; int len,n,m,len1; LL ans[maxn],f[maxn]; void tim(int x){ LL tmp = 0, pre = 0; for(int i = 1; i <= len; ++ i){ tmp = (LL)x * ans[i]; ans[i] = tmp % p + pre; pre = tmp / p; } if(pre) len++, ans[len] = pre; } void tim1(int x){ LL tmp = 0, pre(0); for(int i = 1; i <= len1; ++ i){ tmp = (LL)x * f[i]; f[i] = tmp % p + pre; pre = tmp / p; } if(pre) len1++, f[len1] = pre; } int cnt(LL x){ int num = 0; while(x) num++, x /= 10; return num; } void re(){ LL pre = 0; for(int i = 1; i <= len; ++ i){ if(!pre && i > len1) break; ans[i] -= pre; pre = 0; if(ans[i] < f[i]) ans[i] = ans[i] + (p - f[i]), pre = 1; else ans[i] = ans[i] - f[i]; } while(!ans[len] && len){ len--; if(!len) break; } printf("%lld", ans[len]); for(int i = len - 1; i >= 1; -- i){ printf("%010lld", ans[i]); } printf("\n"); } int main(){ scanf("%d%d", &n, &m); ans[++len] = 1; f[++len1] = 1; for(int i = n + 3 - m + 1; i <= n + 3; ++ i) tim(i); for(int i = n + 2 - m + 1; i <= n + 2; ++ i) tim1(i); for(int i = 2; i <= n + 2; ++ i){ tim(i); if(i <= n + 1) tim1(i); } tim1(2); re(); //printf("%lld\n", p); return 0; }