BZOJ4807:車(组合数学,高精度)

Description

众所周知,車是中国象棋中最厉害的一子之一,它能吃到同一行或同一列中的其他棋子。車跟車显然不能在一起打起来,于是rly一天又借来了许多许多的車在棋盘上摆了起来……他想知道,在N×M的矩形方格中摆最多个数的車使其互不吃到的情况下方案数有几种。
但是,由于上次摆炮摆得实在太累,他为了偷懒,打算增加一个条件:对于任何一个車A,如果有其他一个車B在它的上面(車B行号小于車A),那么車A必须在車B的右边(車A列号大于車B)。棋子都是相同的。

Input

一行,两个正整数N和M。
N<=1000000,M<=1000000

Output

一行,输出方案数的末尾50位(不足则直接输出)。

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 }
posted @ 2018-09-24 15:34  Refun  阅读(201)  评论(0编辑  收藏  举报