【数学】一次不定方程非负整数解个数
一次不定方程非负整数解个数
前置定理:
\(\frac{1}{1-x}=\sum^{\infty}_{r=0}x^r\)
\(\frac{1}{1-sx}=\sum^{\infty}_{r=0}s^rx^r\)
\(\frac{1}{(1-x)^n}=\sum^{\infty}_{r=0}C^{n-1}_{n+r-1}x^r=\sum^{\infty}_{r=0}C^{r}_{n+r-1}x^r\)
-
定理 \(1\) :
一次不定方程
\[x_1+x_2+\dots+x_n=r\tag{1.1} \]的非负整数解的个数等于 \(C_{n+r-1}^r=C_{n+r-1}^{n-1}\) .
证:
设方程 \((1.1)\) 有 \(a_r\) 个非负整数解。 不难发现,数列 \(a_0,a_1,a_2,\dots,a_r,\dots\) 的母函数就是
\[\underbrace{(1+x+x^2+\dots+x^k+\dots)(1+x+x^2+\dots+x^k+\dots)\dots\\(1+x+x^2+\dots+x^k+\dots)}_{n 个}\tag{1.2} \]事实上,式 \((1,2)\) 的展开式中每个 \(x^r\) 必可写成
\[x^r=x^{m_1}\cdot x^{m_2}\dots x^{m_n}=x^{m_1+m_2+\dots+m_n}\tag{1.3} \]这里 \(x^{m_1},x^{m_2},\dots,x^{m_n}\) 分别取自第 \(1,2,\dots,n\) 个括号,显然 \(m_1,m_2\dots,m_n\) 都是非负整数。由式 \((1.3)\) 可知
\[m_1+m_2+\dots+m_n=r \]故 \((m_1,m_2,\dots,m_n)\) 是方程 \((1.1)\) 的一个非负整数解。 这就是说式 \((1.2)\) 中每一项 \(x^r\) 对应方程 \((1.1)\) 的一个非负整数解 \((m_1,m_2,\dots,m_n)\) ;方程 \((1.1)\) 的每一个非负整数解也对应式 \((1.2)\) 的一项 \(x^r\) 。因此方程 \((1.1)\) 的非负整数解的个数 \(a_r\) 就等于式 \((1.2)\) 中 \(x^r\) 的项数。合并同类项后, \(a_r\) 就等于 \(x^r\) 的系数。从而式 \((1.2)\) 就是 \(\{a_r\}\) 的母函数。
又式 \((1.2)\) 等于 \(\frac{1}{1-x}\cdot\frac{1}{1-x}\dots\frac{1}{1-x}=\frac{1}{(1-x)^n}\) ,即
\[\frac{1}{(1-x)^n}=a_0+a_1x+a_2x^2+\dots+a_rx^r\dots\;, \]故由前置定理可得
\[a_r=C^{r}_{n+r-1}\;(r=0,1,2,\dots) \] -
推论:
不定方程 \(x_1+x_2+\dots+x_n=r\) 的正整数解的个数为 \(C^{n-1}_{r-1}\) 。
证:
作变换:\(x_1=y_1+1,x_2=y_2+1,\dots,x_n=y_n+1\) ,则原方程可化为
\[y_1+y_2+\dots+y_n=r-n . \]当 \(x_1,x_2\dots,x_n\) 取正整数时,\(y_1,y_2,\dots,y_n\) 取非负整数值。这样问题就转化为求上面关于 \(y_1,y_2,\dots,y_n\) 的方程的非负整数解的个数。由定理 \(1\) 可知非负整数解的个数为
\[C^{r-n}_{n+(r-n)-1}=C^{r-n}_{r-1}=C_{r-1}^{n-1 } . \] -
定理 \(2\) :
设方程 \(s_1x_1+s_2x_2+\dots+s_nx_n=r\) 的非负整数解的个数为 \(b\) ,则 \(b_r\) 的母函数是
\[\frac{1}{(1-x^{s_1})(1-x^{s_2})\dots(1-x^{s_n})} \]这里 \(s_1,s_2,\dots,s_n\) 都是正整数。
-
例 \(1\) :
试求方程 \(x+y+z=24\) 的整数解的个数,要求 \(x>1,y>2,z>3\) 。
解:
作变换: \(x=X+2,y=Y+3,z=Z+4\) ,则问题转化为求方程 \(X+Y+Z=15\) 的非负整数解的个数。由定理 \(1\) ,得解的个数为
\[C^{15}_{3+15-1}=C^{2}_{17}=136 \] -
例 \(2\) :
试求方程 \(x_1+x_2+x_3+x_4=23\) 的正整数解的个数,要求 \(x_1\leq9,x_2\leq8,x_3\leq7,x_4\leq6\) 。
解:
设方程 \(x_1+x_2+x_3+x_4=r\) 满足条件的 \(x_1\leq9,x_2\leq8,x_3\leq7,x_4\leq6\) 的正整数解的个数为 \(a_r\) ,则 \(a_r\) 的母函数为
\[(x+x^2+\dots+x^9)(x+x^2+\dots+x^8)(x+x^2\dots+x^7)(x+x^2+\dots+x^6) \]易知上式的展开式中 \(x^{23}\) 的系数 \(a_{23}\) 就是问题的解。而 \(a_{23}\) 又是
\[f(x)=(1+x+x^2+\dots+x^8)(1+x+x^2+\dots+x^7)\\(1+x+x^2\dots+x^6)(1+x+x^2+\dots+x^5) \]的展开式中 \(x^{19}\) 的系数,上式等于
\[f(x)=\frac{(1-x^9)(1-x^8)(1-x^7)(1-x^6)}{(1-x)^4} \]因为 \(\frac{1}{(1-x)^4}=\sum_{r=0}^{\infty}C_{r+3}^3x^r\) ,把 \(f(x)\) 的分子展开,并去掉次数高于 \(19\) 的项,问题就转化为求
\[(1-x^6-x^7-x^8-x^9+x^{13}+x^{14}+2x^{15}+x^{16}+x^{17})\sum_{r=0}^{\infty}C_{r+3}^3x^r \]展开式中 \(x^{19}\) 的系数,易知它等于
\[C_{22}^3-C_{16}^3-C_{15}^3-C_{14}^3-C_{13}^3+C_9^3+C_8^3+2C_7^3+C_6^3+C_5^3=115 \] -
例题
1,P3301 方程
题意:
给定方程
\[X_1+X_2+\dots+X_n=M \]有限制如下:
\[\begin{align*} &X_1\leq A_1\\&X_2\leq A_2\\&\dots\\&X_{n_1}\leq A_{n_1},\\\\&X_{n_1+1}\geq A_{n_1+1}\\&X_{n_1+2}\geq A_{n_1+2}\\&\dots\\&X_{n_1+n_2}\geq A_{n_1+n_2} \end{align*} \]其中 \(n_1+n_2\leq n,\;n\leq 1e^9,n_1\leq8,n_2\leq8,m\leq1e^9\)。
求:满足这些限制的前提下,该方程正整数解的个数。答案对 \(p\) 取模。 \(p\in\{10007,262203414,437367875\}\) 。
解:
对于所有含限制 \(X_i\geq A_i\) 的 \(X_i\) 做变换:
\[X_i=X_i-A_i\\M-=A_i \]则 \(X_i\) 的限制变为 \(X_i\geq0\) 。
则,给定方程的解的个数 \(a_M\) 为
\[\begin{align*} f(x)&=\frac{1}{(1-x)^{n-n_1}}\times \frac{\prod_{i=1}^{n_1}(1-x^{A_i})}{(1-x)^{n_1}}\\&=\frac{\prod_{i=1}^{n_1}(1-x^{A_i})}{(1-x)^n} \end{align*} \]的展开式中 \(x^{M}\) 的系数。
剩下做法同例2。
#include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) #define mkp(a,b) make_pair(a,b) using namespace std; typedef long long ll; const int maxn=1e6+5; const int inf=0x3f3f3f3f; ll exgcd(ll a,ll b,ll &x,ll &y){ if(!b){ x=1;y=0; return a; } ll g=exgcd(b,a%b,x,y); ll t=x; x=y; y=t-a/b*y; return g; } ll inv(ll a,ll b) { ll x=0,y=0; exgcd(a,b,x,y); x=(x%b+b)%b; if(!x)x+=b; return x; } ll kpow(ll a,ll b,ll p) { ll ans=1; while(b){ if(b&1)ans=ans*a%p; a=a*a%p; b>>=1; } return ans; } ll Y[maxn]; ll calc(ll n,ll p,ll pk,ll yy) { if(!n)return 1; ll x=calc(n/p,p,pk,yy),y=1; ll z=1; // for(ll i=1;i<=pk;i++) // if(i%p)y=y*i%pk; y=kpow(yy,n/pk,pk); for(ll i=n/pk*pk;i<=n;i++) if(i%p)z=z*i%pk; return x*y%pk*z%pk; } ll G(ll n,ll p){ if(n<p)return 0; return n/p+G(n/p,p); } ll fac[maxn],w[maxn],b[maxn],k,tw[maxn]; ll exLucas(ll n,ll m,ll p) { for(int i=1;i<=k;i++) { tw[i]=w[i]; b[i]=kpow(fac[i],G(n,fac[i])-G(m,fac[i])-G(n-m,fac[i]),w[i]); b[i]=b[i]*calc(n,fac[i],w[i],Y[i])%w[i]*inv(calc(m,fac[i],w[i],Y[i]),w[i])%w[i]*inv(calc(n-m,fac[i],w[i],Y[i]),w[i])%w[i]; } ll d; for(int i=2;i<=k;i++) { d=__gcd(tw[i-1],tw[i]); b[i]=inv(tw[i-1]/d,tw[i]/d)*((b[i]-b[i-1])/d)%(tw[i]/d)*tw[i-1]+b[i-1]; tw[i]=tw[i-1]*tw[i]/d; b[i]=(b[i]%tw[i]+tw[i])%tw[i]; } return b[k]; } ll A[maxn]; map<ll,ll>mp,tmp;// <指数,系数> int main() { int T,p,pp; scanf("%d%d",&T,&p); pp=p;k=0; for(int i=2,t;i*i<=pp;i++) if(pp%i==0){ t=1; while(pp%i==0)pp/=i,t*=i; w[++k]=t;fac[k]=i; } if(pp!=1){ w[++k]=pp;fac[k]=pp; } for(int i=1;i<=k;i++) { Y[i]=1; for(ll j=1;j<=w[i];j++) if(j%fac[i])Y[i]=Y[i]*j%w[i]; } while(T--) { mp.clear(); ll n,n1,n2,m,x,r; scanf("%lld%lld%lld%lld",&n,&n1,&n2,&m); for(int i=1;i<=n1;i++)scanf("%lld",&A[i]); for(int i=1;i<=n2;i++){ scanf("%lld",&x); m-=x; } m-=(n-n2); if(m<0){ puts("0");continue; } mp[0]=1; ll c,d; for(int i=1;i<=n1;i++) { tmp.clear(); for(auto x:mp){ c=x.first;d=x.second;// dx^c - dx^(c+a[i]) tmp[c]+=d; tmp[c+A[i]]-=d; } mp=tmp; } ll res=0; for(auto x:mp){ c=x.first;d=x.second; if(c>m)continue; r=m-c; res=(res+d*exLucas(n+r-1,n-1,p)%p+p)%p; } printf("%lld\n",res); } }
2,背包
题意:
给定方程:
\[x_1+x_2+x_3+2x_4+2x_5+1+4x_6+x_7+3x_8=n \]亦即:
\[x_1+x_2+x_3+2x_4+2x_5+4x_6+x_7+3x_8=n-1 \]其中,限制:
\[x_1\leq 1\\x_2\leq2\\x_3\leq 3\\x_7\leq1 \]求解方程非负整数解个数。
解:
对于 \(x_1+x_2+x_3+x_7\) 有母函数:
\[(1+x)(1+x+x^2)(1+x+x^2+x^3)(1+x) \]即:
\[\frac{(1-x^2)(1-x^3)(1-x^4)(1-x^2)}{(1-x)^4} \]对于 \(2x_4+2x_5+4x_6+3x_8\) 有母函数(定理2):
\[\frac{1}{(1-x^2)(1-x^2)(1-x^4)(1-x^3)} \]则,对于原方程有母函数:
\[\begin{align*} f(x)&=\frac{(1-x^2)(1-x^3)(1-x^4)(1-x^2)}{(1-x)^4}\times\frac{1}{(1-x^2)(1-x^2)(1-x^4)(1-x^3)}\\ &=\frac{1}{(1-x)^4} \end{align*} \]则,原方程的解的个数为 \(f(x)\) 中 \(x^{n-1}\) 的系数,即 \(C_{4+(n-1)-1}^{3}=C_{n+2}^3\) 。
#include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) #define mkp(a,b) make_pair(a,b) using namespace std; typedef long long ll; const int maxn=1e6+5; const int inf=0x3f3f3f3f; const int mod=1e9+7; int c[4]={1,1,500000004,333333336}; int main() { ll n; scanf("%lld",&n); ll res=1; for(ll i=n+2,j=1;j<=3;i--,j++)res=res*(i%mod)%mod*c[j]%mod; printf("%lld\n",res); }