• 车(唯一分解定理+高精度乘以单精度)


    题目描述:
    众所周知,车是中国象棋中最厉害的一子之一,它能吃到同一行或同一列
    中的其他棋车。车跟车显然不能在一起打起来,于是rly一天又借来了许多许多的车在棋盘上摆了起来……他想知道,在N×M的矩形方格中摆最多个数的车使其互不吃到的情况下方案数有几种。但是,由于上次摆炮摆得实在太累,他为了偷懒,打算增加一个条件:对于任何一个车A,如果有其他一个车B在它的上方(车B行号小于车A),那么车A必须在车B的右边(车A列号大于车B)。
    棋子都是相同的。
    输入说明:
    一行,两个正整数N和M。
    输出说明:
    一行,输出方案数的末尾50位(不足则直接输出)。
    样例输入:
    2 2
    样例输出:
    1
    数据范围:
    对于20%的数据, N<=10, M<=10。
    对于40%的数据, N<=40, M<=40。
    对于70%的数据, N<=10000, M<=10000。
    对于100%的数据, N<=1000000, M<=1000000。
    思路:
    观察后可以发现答案为C(n,m)(n>m)
    因为C(n,m)=!n/!m*!(n-m)用唯一分解定理分解的变形快速分解!n,!m,!(n-m)
    最后高精度乘以单精度求出乘积即可。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int maxn=1000010;
    int n,m,tot,a[maxn],prime[maxn],ans[maxn];
    int sa[maxn],sb[maxn];
    bool flag[maxn];
    void prepare()
    {
        for(int i=2;i<=n;i++)
        if(!flag[i])
        {
            prime[++tot]=i;
            for(int j=i+i;j<=n;j+=i)
            flag[j]=1;
        }
        for(int i=1;i<=tot;i++)
        {
            int t=n;
            while(t)
            {
                a[i]+=t/prime[i];
                t/=prime[i];
            }
        }
        for(int i=1;i<=tot;i++)
        {
            int t=m;
            while(t)
            {
                a[i]-=t/prime[i];
                t/=prime[i];
            }
        }
        for(int i=1;i<=tot;i++)
        {
            int t=n-m;
            while(t)
            {
                a[i]-=t/prime[i];
                t/=prime[i];
            }
        }
    }
    void mul(int *a,int b)
    {
        for(int i=1;i<=min(a[0],52);i++)
        a[i]=a[i]*b;
        for(int i=1;i<=min(a[0],52);i++)
        {
            a[i+1]=a[i+1]+a[i]/10;
            a[i]%=10;
        }
        while(a[a[0]+1]&&a[0]<=52)
        {
            a[0]++;
            a[a[0]+1]=a[a[0]+1]+a[a[0]]/10;
            a[a[0]]%=10;
        }
    }
    int main()
    {
        freopen("rook.in","r",stdin);
        freopen("rook.out","w",stdout);
        scanf("%d%d",&n,&m);
        if(n<m) swap(n,m);
        prepare();
        ans[0]=1,ans[1]=1;
        for(int i=1;i<=tot;i++)
          for(int j=1;j<=a[i];j++)
          mul(ans,prime[i]);
        if(ans[0]<=50)
        for(int i=ans[0];i>=1;i--)
        cout<<ans[i];
        else
        for(int i=50;i>=1;i--)
        cout<<ans[i];
        fclose(stdin);fclose(stdout);
        return 0;
    }
  • 相关阅读:
    Gradview读取Excel表并插入数据库
    键盘上每个键作用!!! (史上最全的)­
    经典SQL语句大全
    [转帖] 一个老乞丐的一句话,震惊全中国人!
    GridView控件实现自定义数字、时间、货币字符串格式
    .net连接数据库相关
    论坛Email验正的正则表达式升级
    自定义DBHelper类
    在线编辑器CuteEditor使用方法
    asp.net中验证码的生成
  • 原文地址:https://www.cnblogs.com/cax1165/p/6070891.html
Copyright © 2020-2023  润新知