• BZOJ4737 组合数问题(卢卡斯定理+数位dp)


      不妨不管j<=i的限制。由卢卡斯定理,C(i,j) mod k=0相当于k进制下存在某位上j大于i。容易想到数位dp,即设f[x][0/1][0/1][0/1]为到第x位时是否有某位上j>i,是否卡n、m的限制的方案数。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 100
    #define P 1000000007
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    ll n,m;
    int T,k,ans,f[N][2][2][2],a[N],b[N];
    void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
    int calc(ll n,ll m)
    {
        int t=-1;
        while (n) a[++t]=n%k,n/=k;
        for (int i=0;i<=t;i++) b[i]=m%k,m/=k;
        memset(f,0,sizeof(f));
        f[t+1][0][1][1]=1;
        for (int i=t;~i;i--)
            for (int j=0;j<=1;j++)
                for (int x=0;x<=1;x++)
                    for (int y=0;y<=1;y++)
                        for (int p=x;p<=1;p++)
                            for (int q=y;q<=1;q++)
                            {
                                int ln=x==1?a[i]:0,rn=x==1?a[i]:(p==1?a[i]-1:k-1),lm=y==1?b[i]:0,rm=y==1?b[i]:(q==1?b[i]-1:k-1);
                                int s=0;
                                for (int u=ln;u<=rn;u++)
                                    for (int v=lm;v<=rm;v++)
                                    if (v<=u) s++;
                                inc(f[i][j][x][y],1ll*f[i+1][j][p][q]*s%P);
                                if (j) inc(f[i][j][x][y],1ll*f[i+1][j-1][p][q]*((rn-ln+1)*(rm-lm+1)-s)%P),
                                inc(f[i][j][x][y],1ll*f[i+1][j][p][q]*((rn-ln+1)*(rm-lm+1)-s)%P);
                            }
        return ((f[0][1][0][0]+f[0][1][0][1])%P+(f[0][1][1][0]+f[0][1][1][1])%P)%P;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4737.in","r",stdin);
        freopen("bzoj4737.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        T=read(),k=read();
        while (T--)
        {
            cin>>n>>m;m=min(n,m);
            if (m&1) ans=(P-(m%P)*((m+1>>1)%P)%P)%P;
            else ans=(P-((m+1)%P)*((m>>1)%P)%P)%P;
            inc(ans,calc(n,m));
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    主机不能访问虚拟机CentOS中的站点
    linux安装redis
    java获去json所有对象
    Java nio和io
    [shell基础]——if/for/while/until/case 语句
    [shell基础]——整数比较;字符串比较;文件测试;逻辑测试符
    [shell基础]——数组
    [shell基础]——I/O重定向
    [shell基础]——tr命令
    [shell基础]——split命令
  • 原文地址:https://www.cnblogs.com/Gloid/p/9955249.html
Copyright © 2020-2023  润新知