您的位置:首页 > 其它

[BZOJ]4807: 車 组合数学+高精度

2017-09-22 16:22 399 查看
Description

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

题解:

我本来以为这是一道水题,答案想了一会儿发现是Cmin(n,m)max(n,m),于是就打了个质因数分解加高精度,结果发现慢的一皮,反复优化无果。最后才发现,原来是结构体里的v数组开太大,每次乘都要重新定义一次,所以就慢,改了这个很快AC了。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1000010;
const int M=100;
struct A{int v[30],len;}C;
A operator * (A a,int b)
{
A c=a;c.len=min(c.len,25);
for(int i=1;i<=c.len;i++)c.v[i]*=b;
for(int i=1;i<=c.len;i++)
{
c.v[i+1]+=c.v[i]/M;
c.v[i]%=M;
}
while(c.v[c.len+1])
{
c.v[c.len+1]+=c.v[c.len]/M;
c.v[c.len]%=M;
c.len++;
}
c.len=min(c.len,25);
return c;
}
int n,m,k[maxn];
int prime[maxn],pr=0;
int v[maxn];
void pre()
{
for(int i=2;i<=n;i++)
{
if(!v[i])
{
v[i]=i;
prime[++pr]=i;
}
for(int j=1;j<=pr&&i*prime[j]<=n;j++)
{
v[i*prime[j]]=prime[j];
if(i%prime[j]==0)break;
}
}
}
void work(int x,int y)
{
while(x!=1)
{
k[v[x]]+=y;
x/=v[x];
}
}
int main()
{
scanf("%d%d",&n,&m);
if(n<m)swap(n,m);pre();
for(int i=m+1;i<=n;i++)work(i,1);
for(int i=2;i<=n-m;i++)work(i,-1);
C.v[1]=1;C.len=1;
for(int i=1;i<=n;i++)
while(k[i]--)C=C*i;
printf("%d",C.v[C.len]);
for(int i=C.len-1;i;i--)
printf("%02d",C.v[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: