1 首先 ans=c(n,a[0] )*c(n-a[0],a[1])*(n-a[0]-a[1],a[2])......
a[i]: 含义 在数列中i的个数有a[i]个
2 如何判断 x*y>p(1e18LL)--->乘法变除法 p/x<y
3 如何判断组合数 c (n,m)是否溢出 这里采用交叉乘除 c(n,m)=c(n-1,m-1)*(n/m)
想办法先除掉m: 1)t=gcd(n,m) n/=t m/=t
2) k=c(n-1,m-1)/m
3) 再判断 k*n 是否溢出
其实m最大为20左右。。。
法二: 判断C(n,m)是否溢出 可把每一个数分解为素数的乘积,用加减法代替乘除法 (代码是法一)
1106: xry111的排列
时间限制: 4 Sec 内存限制: 128 MB提交: 122 解决: 11
[提交][状态][讨论版]
题目描述
fpcsong有一天闲着无聊,就拿了一张纸,写下了n个数a1, a2, ..., an,问xry111这些数的全排列的个数是多少。xry111说不就是n!么,然而fpcsong说你个SB,这些数有好多重复的。于是xry111就傻眼了,快帮帮他吧。
fpcsong讨厌高精度,所以如果答案超过了1018,就输出“Look, shability!”。
输入
多组数据(最多100组)。
每组数据,第1行,一个整数n。之后1行,包含n个整数a1, a2, ..., an,用空格分割。
对于90%的数据,有0<n≤100。
对于100%的数据,有0<n≤106,0≤ai≤1000。
注意:输入文件较大,请使用较快的IO。
输出
对于每组数据输出1行,若答案不超过1018,输出答案,否则输出“Look, shability!”。
样例输入
4
0 0 0 1
20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
20
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
样例输出
4
Look, shability!
1
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 typedef long long LL; 6 const LL p=1e18; 7 int a[1005],n; 8 int gcd (int a,int b) { 9 return !b?a:gcd(b,a%b); 10 } 11 LL C (int n,int m) { 12 if (n-m<m) m=n-m; 13 LL sum=1; int k=1; 14 for (int i=n-m+1;i<=n;i++,k++) { 15 int d=gcd (i,k); 16 int t1=i/d; int t2=k/d; 17 LL x=sum/(LL)t2; sum=x*(LL)t1; 18 if (sum<=0||sum>p||p/x<t1) return 0; 19 } 20 return sum; 21 } 22 int main () 23 { 24 while (~scanf ("%d",&n)) { 25 memset (a,0,sizeof(a)); int _max=0; 26 for (int i=1;i<=n;i++) { 27 int x; scanf ("%d",&x); 28 a[x]++; _max=max (_max,x); 29 } 30 int x=n; LL ans=1; bool flag=1; 31 for (int i=0;i<=_max;i++) { 32 if (a[i]) { 33 LL t1=ans; 34 LL t2=C (x,a[i]); 35 ans*=t2; 36 if (ans<=0||ans>p||p/t1<t2) { flag=0; break;} 37 x-=a[i]; 38 } 39 } 40 if (!flag) printf ("Look, shability!\n"); 41 else printf ("%lld\n",ans); 42 } 43 return 0; 44 }
!!永远记住代码不重要,思想最重要。。。
抓住青春的尾巴。。。