Comet OJ - 模拟赛 #2 Day1 小猪佩奇跳格子
求解ax+by=n x,y为非负数的解的个数 ,答案对10007取模
(然后这道题x个a和y个b的顺序不同,算作不同)
然后数据范围:a,b,n<=10^9 。
当场翻了数论书,有这几个点:
1,对于二元一次不定方程ax+by=c,有整数解的充要条件是 (a,b)|c。
2,若(a,b)=1,且不定方程有整数解x=x0,y=y0,则它的一切整数解可表示成:
x=x0+bt; y=y0-at; (t为任意整数)
所以做法是先判断有没有解,然后有的话 就除去它们的公因数,然后由xy的非负性判断t的范围
然后因为这道题x个a和y个b的顺序不同,算作不同,然后就是组合数了,然后因为是小模,所以是lucas定理。。。
(我居然现场翻书学的lucas,大一学的然后忘了。。可怕QAQ
#include<bits/stdc++.h> #define debug1 printf("!"); #define debug2 puts("#"); using namespace std; typedef long long ll; const int mod=1e4+7; const int maxn=1e7+50; const int inf=0x3f3f3f3f; ll jc[mod+50]; ll kpow(ll a,ll b) { a%=mod; ll ans=1; while(b) { if(b&1)ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans; } ll C(ll n,ll m){ if(m>n)return 0; return ((jc[n]*kpow(jc[m],mod-2))%mod*kpow(jc[n-m],mod-2)%mod); } ll Lucas(ll n,ll m){ if(!m)return 1; return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod; } inline void init() { jc[0]=1; for(int i=1;i<=mod;i++) { jc[i]=(jc[i-1]*i)%mod; } } int f[maxn]; inline void find(ll a,ll b,ll c,ll&x,ll&y) { //t=c/a;tt=c%a; //x=t+(tt-b*y)/a a|(tt-b*y) ll t=c/a,tt=c%a; y=0; while((tt-b*y)%a)y++; x=t+(tt-b*y)/a; return; } int main() { init(); ll n,a,b,d; scanf("%lld%lld%lld",&n,&a,&b); if(a>b)swap(a,b); d=__gcd(a,b); if(n%d!=0) { puts("0");return 0; } n/=d;a/=d;b/=d; if(n<maxn) { f[0]=1; for(int i=1;i<=n;i++) { if(a<=i)f[i]=(f[i]+f[i-a])%mod; if(b<=i)f[i]=(f[i]+f[i-b])%mod; // printf("<%d %d>",f[i],i); } printf("%d",f[n]); return 0; } ll x0,y0,x,y; find(a,b,n,x0,y0); // printf("{x0=%lld,y0=%lld}\n",x0,y0); ll up=y0/a,down=-x0/b; // printf("{down=%lld,up=%lld}",down,up); ll ans=0; for(int t=down;t<=up;t++) { x=x0+b*t;y=y0-a*t; if(t<0&&x<0)break; if(t>0&&y<0)break; if(x<0||y<0||x>n||y>n)continue; // printf("<%lld %lld>",x,y); ans=(ans+Lucas(x+y,min(x,y)))%mod; } printf("%lld\n",ans); return 0; }