牛牛P50591 解的分配问题,高精度组合数

题意:

给出不定方程
a 1 + a 2 + . . . + a k = x x   ( m o d   1000 ) a_{1}+a_{2}+...+a_{k}=x^{x}\ (mod\ 1000) a1+a2+...+ak=xx (mod 1000)
求出有多少组正整数解

Solution:

解的分配问题考虑隔板法,两个隔板之间的小球数是一个解,每个隔板之前的到前一个隔板的小球数就是一个解,第一个小球前不用放置一个隔板,但最后一个小球后面一定需要放置一个隔板,那么只需要在剩下的 x x ( m o d   1000 ) − 1 x^{x}(mod\ 1000)-1 xx(mod 1000)1个位置中放置 k − 1 k-1 k1个隔板,即
C x x ( m o d   1000 ) − 1 k − 1 C_{x^{x}(mod\ 1000)-1}^{k-1} Cxx(mod 1000)1k1
这个需要高精度加法或乘法,切莫使用NTT做,自带取余,可以考虑FFT求高精度积,总而言之,高精度加是最优的

也可以考虑生成函数,每个解的生成函数为
f ( x ′ ) = ∑ i = 1 x x ( m o d   1000 ) x ′ i f(x')=\sum_{i=1}^{x^{x}(mod\ 1000)}x'^{i} f(x)=i=1xx(mod 1000)xi
对这个多项式求 k k k次幂即可,但数字太大,不如高精度,并且需要NTT,自带取余,会使得答案不准确

// #include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<vector>
#include<bitset>
#include<map>
using namespace std;

using ll=long long;
const int N=2e7,inf=0x3fffffff;
const long long INF=0x3f3f3f3f3f3f,mod=1e3;

ll qpow(ll a,ll b)
{
	ll ret=1,base=a;
	while(b)
	{
		if(b&1) ret=ret*base%mod;
		base=base*base%mod;
		b>>=1;
	}
	return ret;
}

vector<int>operator+(vector<int>val1,vector<int>val2)
{
    if(val1.size()<val2.size()) swap(val1,val2);
    reverse(val1.begin(),val1.end()); reverse(val2.begin(),val2.end());
    vector<int>ret(val1.size());
    for(int i=0;i<val2.size();i++) ret[i]=val1[i]+val2[i];
    for(int i=val2.size();i<val1.size();i++) ret[i]=val1[i];
    for(int i=0;i<ret.size();i++)
    {
        if(ret[i]>9)
        {
            if(i+1<ret.size()) ret[i+1]+=ret[i]/10;
            else ret.push_back(ret[i]/10);
            ret[i]%=10;
        }
    }
    reverse(ret.begin(),ret.end());
    return ret;
}

ll k,x;
vector<int>C[1005][105];

int main()
{
    #ifdef stdjudge
        freopen("in.txt","r",stdin);
    #endif 
    cin>>k>>x;
    ll tmp=qpow(x,x);
    C[0][0]={1};
    for(int i=1;i<=tmp;i++)
    {
        for(int j=0;j<=105;j++)
        {
            if(j==0||j==i) C[i][j]={1};
            else C[i][j]=C[i-1][j-1]+C[i-1][j];
        }
    }
    if(k>tmp) cout<<0;
    else
    {
        for(int i=0;i<C[tmp-1][k-1].size();i++) printf("%d",C[tmp-1][k-1][i]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值