【loj6142】「2017 山东三轮集训 Day6」A 结论题+Lucas定理

题解:

当奇数

发现答案就是C(n,1)^2+C(n,3)^2+。。。C(n,n)^2

倒序相加,发现就是C(2n,n) 所以答案就是C(2n,n)/2

当偶数

好像并不会证

打表出来可以得到

2.当n为偶数且为4的倍数时,答案为C(2n,n)+C(n,n/2)/2

3.当n为偶数且不为4的倍数时,答案为C(2n,n)-C(n,n/2)/2

另外Claris告诉我在p较小时可以数位dp来求

先用lucas定理 C(n,m)=C(n%p,m%p)*C(n/p,m/p)

然后我们就可以把n表示成p进制

答案就是m在p进制下和对应n求C的乘积

然后我们可以数位dp这个东西

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define rint register ll
#define IL inline
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
const ll p=1000003
;
const ll mo=1000003
;
const ll INF=1e18;
const ll N=2e6;
ll n,cnt=0,a[50],jc1[N],jc2[N],f[N][2][2];
void gcd(ll x,ll y,ll &a,ll &b)
{
  if (y==0)
  {
    a=1; b=0; return;
  }
  gcd(y,x%y,b,a);
  b-=a*(x/y);
}
ll C(ll x,ll y)
{
  if (x<y) return(0);
  return jc1[x]*jc2[y]%p*jc2[x-y]%p;
}
void jf(ll &x,ll y)
{
  x+=y;
  if (x>p) x-=p;
}
int main()
{
  cin>>n;
  while (n) a[++cnt]=n%p,n/=p;
  jc1[0]=jc2[0]=1;
  rep(i,1,p)
  { 
    jc1[i]=(jc1[i-1]*i)%p;
    jc1[i]=(jc1[i]+p)%p;
    ll x,y;
    gcd(i,p,x,y);
    jc2[i]=(jc2[i-1]*x)%p;
    jc2[i]=(jc2[i]+p)%p;
  }
  f[cnt+1][0][0]=1;
  dep(j,cnt,1)
  {
    ll tmp1j=0,tmp1o=0;
    rep(i,0,a[j]-1)
    {
      ll kk=C(a[j],i);
      kk=(kk*kk)%mo;
      if (i%2)
        jf(tmp1j,kk);
      else jf(tmp1o,kk);
    }
    f[j][0][1]=(f[j+1][0][0]*tmp1o%mo+f[j+1][1][0]*tmp1j%mo)%mo;
    f[j][1][1]=(f[j+1][0][0]*tmp1j%mo+f[j+1][1][0]*tmp1o%mo)%mo;
    if (a[j]%2) jf(tmp1j,1); else jf(tmp1o,1);
    f[j][0][1]+=(f[j+1][0][1]*tmp1o%mo+f[j+1][1][1]*tmp1j%mo)%mo;
    f[j][1][1]+=(f[j+1][0][1]*tmp1j%mo+f[j+1][1][1]*tmp1o%mo)%mo;
    if (f[j+1][1][0]) f[j][(1+a[j])%2][0]=1;
    else f[j][a[j]%2][0]=1;
  }
  ll ans=(f[1][0][1]+f[1][0][0])%mo;
  cout<<ans<<endl;
}
原文地址:https://www.cnblogs.com/yinwuxiao/p/9407826.html