6476. 【GDOI2020模拟02.19】A(范德蒙恒等式)

题目描述


题解

镇♂男则反

容斥下界,上界开到大概505位,数位dp最终的和V

设边界(要大于边界)之和为S,那么答案为C(V-S-1,n-1)

根据范德蒙恒等式,C(n+m,k)=∑C(n,i)*C(m,k-i)

如果nm都是正数很好证明,把n+m分成n和m两部分,枚举n部分选择个数组合一下

这个式子其实可以拓展到负数,证明要用生成函数

关于n为负数的组合数:\(C(n,m)=n^{\underline{m}}/m!\),其实和正数时是一样的

(注意这只是为了计算范德蒙恒等式而扩展的,在一般情况下当n<m时结果0)

于是C(V-S-1,n-1)=∑C(V,i)*C(-S-1,n-1-i)

对于每个i维护合法的V(V>=S+n)的∑C(V,i),转移相当于求∑C(V+D^j,i),等于∑(∑C(V,j))*C(D^j,i-j)

瞎写的时间应该是O(2^n*D^2*n^3),把组合数预处理即可变成O(2^n*D*n^2)

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define mod 1000000007
#define Mod 1000000005
#define ll long long
#define N 505
#define file
using namespace std;

ll w[13],L[13][N+1],R[13][N+1],c[N+1],b[1401],f[N+1][12][2],g[N+1][501][12],ans,s,S;
int d[13],n,D,i,j,k,l,len;
bool bz[501];
char ch;

ll qpower(ll a,int b)
{
    ll ans=1;
    
    while (b)
    {
        if (b&1)
        ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    
    return ans;
}

void swap(ll &x,ll &y)
{
    int z=x;x=y;y=z;
}

void turn(ll *a)
{
    int i,j,k,l=0;
    
    while (len)
    {
        b[0]=0;
        fd(i,len,1)
        b[i-1]+=(b[i]%D)*10,b[i]/=D;
        
        a[++l]=b[0]/10;
        while (len && !b[len]) --len;
    }
}

void Read()
{
    int i,j,k,l;
    
    len=0;
    
    ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9') b[++len]=ch-'0',ch=getchar();
    
    fd(i,len/2,1) swap(b[i],b[len-i+1]);
}

void add(ll *a,ll *b)
{
    int i;
    
    fo(i,1,N)
    {
        a[i]+=b[i];
        if (a[i]>=D)
        a[i]-=D,++a[i+1];
    }
}

void dec(ll *a)
{
    int i;
    
    --a[1];
    fo(i,1,N)
    if (a[i]<0)
    a[i]+=D,--a[i+1];
    else
    break;
}

ll MOD(ll *a)
{
    ll ans=0;
    int i;
    
    fd(i,N,1)
    ans=(ans*D+a[i])%mod;
    
    return ans;
}

ll C(ll n,int m)
{
    ll ans=1;
    int i;
    
    fo(i,1,m) ans=ans*(n-i+1)%mod*w[i]%mod;
    
    return ans;
}

void dp(int type)
{
    int i,j,k,l,I,J,K,L,s1,s2;
    ll s,S;
    
    fd(i,N,1)
    {
        if (c[i] && bz[c[i]])
        {
            fo(k,0,n-1)
            f[i][k][0]=(f[i][k][0]+(g[i][c[i]][k]-g[i][c[i]-1][k]))%mod;
        }
        
        fo(j,0,n-1)
        f[i][j][1]=(f[i][j][1]+(g[i][D-1][j]-g[i][c[i]][j]))%mod;
        
        if (c[i]) break;
    }
    
    fd(i,N,2)
    {
        I=i-1;
        
        fo(j,0,n-1)
        {
            J=j;
            
            fo(l,0,j)
            {
                if (c[I])
                f[I][J][0]=(f[I][J][0]+f[i][l][0]*(g[I][c[I]][j-l]-g[I][c[I]-1][j-l]))%mod;
                else
                f[I][J][0]=(f[I][J][0]+f[i][l][0]*g[I][c[I]][j-l])%mod;
                f[I][J][1]=(f[I][J][1]+f[i][l][0]*(g[I][D-1][j-l]-g[I][c[I]][j-l]))%mod;
                
                f[I][J][1]=(f[I][J][1]+f[i][l][1]*g[I][D-1][j-l])%mod;
            }
        }
    }
    
    s=-MOD(c)-1+n;
    fo(j,0,n-1)
    ans=(ans+(f[1][j][0]+f[1][j][1])*C(s,n-1-j)*type)%mod;
}

void dg(int t,int s)
{
    int i;
    
    if (t>n)
    {
        memset(c,0,sizeof(c));
        memset(f,0,sizeof(f));
        c[1]=n;
        fo(i,1,N) if (c[i]>=D) c[i+1]=c[i]/D,c[i]%=D; else break;
        fo(i,1,n) if (!d[i]) add(c,L[i]); else add(c,R[i]);
        
        dp(s);
        return;
    }
    
    d[t]=0,dg(t+1,s);
    d[t]=1,dg(t+1,-s);
}

int main()
{
    freopen("A.in","r",stdin);
    #ifdef file
    freopen("A.out","w",stdout);
    #endif
    
    scanf("%d%d",&n,&D);
    fo(i,0,D-1)
    scanf("%d",&j),bz[i]=j;
    
    fo(i,1,n)
    {
        w[i]=qpower(i,Mod);
        
        Read(),turn(L[i]),dec(L[i]);
        Read(),turn(R[i]);
    }
    
    S=1;
    fo(i,1,N)
    {
        s=0;
        g[i][0][0]=bz[0];
        fo(j,1,D-1)
        {
            fo(k,0,n-1) g[i][j][k]=g[i][j-1][k];
            s=(s+S)%mod;
            
            if (bz[j])
            {
                fo(k,0,n-1)
                g[i][j][k]=(g[i][j][k]+C(s,k))%mod;
            }
        }
        
        S=S*D%mod;
    }
    
    dg(1,1);
    
    printf("%lld",(ans+mod)%mod);
    
    fclose(stdin);
    fclose(stdout);
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/gmh77/p/12400598.html