0
点赞
收藏
分享

微信扫一扫

方程的解 LibreOJ - 10231(组合计数)

IT影子 2022-03-11 阅读 60

 解题思路:对于这个问题,首先我们要通过快速幂求出n=x^x%1000的值,下面就是找出满足a1+a2+……+ak=n(a1....ak为未知量)的解的组数,这里我们可以采用组合计数中常用的一个方法——隔板法来求得,我们假设有n个小球排成一列,目的是通过加隔板的方式将这些球分成k组,n个小球之间一共有n-1个空隙,我们要做的就是要在这n-1个空隙中添加k-1个隔板(2个隔板不能放在同一个位置),很容易想到就是求C(n-1,k-1),可以 C(n,k)=C(n-1,k-1)+C(n-1,k)来递推计算,采用然而很不幸的是1000!/(100!*900!)最多会有130多位数的结果,所以我们还需要手写下高精度加法,最后从最高一位非0的数开始一位一位输出即可。

上代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=150;
int f[1010][110][N];//这里x的第3维表示f[i][j]的每一位
int k,x;
int qmi(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
        res=res*a%1000;
        a=a*a%1000;
        b>>=1;
    }
    return res;
}
void add(int a[],int b[],int c[])
{
    for(int i=0,t=0;i<N;i++)
    {
        t=(t+b[i]+c[i]);
        a[i]=t%10;
        t/=10;
    }
}
int main()
{
  cin>>k>>x;
  int n=qmi(x%1000,x%1000);//这里的x要模一下1000,不然算出来的n结果不对
  //求C(n-1,k-1)
  for(int i=0;i<n;i++)
    for(int j=0;j<k&&j<=i;j++)
    if(j==0)
    f[i][j][0]=1;
    else
    add(f[i][j],f[i-1][j-1],f[i-1][j]);
    int i=N-1;
    int *g=f[n-1][k-1];
    while(g[i]==0&&i>=0)//相当于去掉前导零
    i--;
    while(i>=0)
    cout<<g[i--];
    return 0;
}
举报

相关推荐

0 条评论