BZOJ4807:車(组合数学,高精度)
原创
©著作权归作者所有:来自51CTO博客作者qq60ffc54300371的原创作品,请联系作者获取转载授权,否则将追究法律责任
Description
众所周知,車是中国象棋中最厉害的一子之一,它能吃到同一行或同一列中的其他棋子。車跟車显然不能在一起打起来,于是rly一天又借来了许多许多的車在棋盘上摆了起来……他想知道,在N×M的矩形方格中摆最多个数的車使其互不吃到的情况下方案数有几种。
但是,由于上次摆炮摆得实在太累,他为了偷懒,打算增加一个条件:对于任何一个車A,如果有其他一个車B在它的上面(車B行号小于車A),那么車A必须在車B的右边(車A列号大于車B)。棋子都是相同的。
Input
一行,两个正整数N和M。
N<=1000000,M<=1000000
Output
Sample Input
2 2
Sample Output
1
Solution
用我的生日对BZOJ总题数取模然后找到了这个题……
显然答案就是$C(max(n,m),min(n,m))$。用欧拉筛加速质因数分解就可以了。
一开始没算复杂度裸上了一个高精然后T成狗……
Code
1 #include<iostream>
2 #include<cstdio>
3 #define N (1000009)
4 using namespace std;
5
6 int n,m,cnt,prime[N],Keg[N],d[N];
7
8 struct bign
9 {
10 int a[55];
11 bign operator * (const int &b) const
12 {
13 bign c;
14 for (int i=1; i<=50; ++i) c.a[i]=0;
15 for (int i=1; i<=50; ++i)
16 {
17 c.a[i]+=a[i]*b;
18 c.a[i+1]+=c.a[i]/10;
19 c.a[i]%=10;
20 }
21 return c;
22 }
23 }ans;
24
25 void Euler()
26 {
27 for (int i=2; i<=n; ++i)
28 {
29 if (!d[i]){d[i]=i; prime[++cnt]=i;}
30 for (int j=1; j<=cnt && i*prime[j]<=n; ++j)
31 {
32 d[i*prime[j]]=prime[j];
33 if (i%prime[j]==0) break;
34 }
35 }
36 }
37
38 void Divide(int x,int opt)
39 {
40 while (x!=1) Keg[d[x]]+=opt, x/=d[x];
41 }
42
43 int main()
44 {
45 scanf("%d%d",&n,&m);
46 if (n<m) swap(n,m);
47 Euler();
48 for (int i=1; i<=n-m; ++i) Divide(i,-1);
49 for (int i=m+1; i<=n; ++i) Divide(i,1);
50
51 ans.a[1]=1;
52 for(int i=2;i<=n;i++)
53 for(int j=1;j<=Keg[i];j++)
54 ans=ans*i;
55
56 int len=50;
57 while (ans.a[len]==0) --len;
58 for (int i=len; i>=1; --i)
59 printf("%d",ans.a[i]);
60 }