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;
}

原文地址:https://www.cnblogs.com/gmh77/p/12400598.html

时间: 2024-11-09 09:54:50

6476. 【GDOI2020模拟02.19】A(范德蒙恒等式)的相关文章

6476. 【GDOI2020模拟02.19】A

题目 题目比较简洁,就不复述了. 思考历程 这让我联想到了不久之前在CF上做的一道题. 但这两道题的差别是很大的,共同点并不是很多. 直接套那题的方法在这题中也顶多拿个40分. 考虑探索新大陆,然而没有成功-- 感觉这题的暴力不好打,最终也没有打部分分-- (所以说我在这题上耗费了1h) 正解 正解的思路比较清奇. 不用说也知道这题要容斥一下,我比赛时一直在想着保留上界,然而正解是保留下界. 如果想到的话也挺显然的,首先用最终的值减去下界,接下来用生成函数去考虑,就相当于\(\frac{1}{(

范德蒙恒等式

[范德蒙恒等式] 甲班有个同学,乙班有个同学,从两个班中选出个一共有种不同的选法.而换一种思维方式从甲班中选取个同学,从乙班中选取个同学,共有种方法,而对所有的就是范德蒙恒等式. 下面的形式也叫范德蒙恒等式.是特殊形式.此形式中,k=n=m.

范德蒙恒等式的证明

今天我们来认识组合数学中一个重要的恒等式---范德蒙恒等式.这个恒等式的表述如下 很自然的公式,接下来一起来看看它的证明,在维基百科上给出了两种方法证明,分别如下 (1)组合方法证明     甲班有个同学,乙班有个同学,从两个班中选出个一共有种不同的选法.而换一种思维方式 从甲班中选取个同学,从乙班中选取个同学,共有种方法,而对所有的 就是 可以看出这两种方法应该是相等的,即 (2)生成函数法证明 由于,对于等式左边有 而对于等式右边有 左右两边一比较可知 成立,证明完毕! 接下来我们看看一些关

CF #404 (Div. 2) D. Anton and School - 2 (数论+范德蒙恒等式)

题意:给你一个由'('和')'组成的字符串,问你有多少个子串,前半部分是由'('组成后半部分由')'组成 思路:枚举这个字符串中的所有'('左括号,它左边的所有'('左括号的个数为num1,它的右边的所有')'右括号的个数为num2, 根据范德蒙恒等式计算得出 代码: #include <bits/stdc++.h> #define ll long long #define maxn 200000 #define mod 1000000007 using namespace std; ll j

CodeForces 785 D Anton and School - 2 范德蒙恒等式

Anton and School - 2 题解: 枚举每个左括号作为必选的. 那么方案数就应该是下面的 1 , 然后不断化简, 通过范德蒙恒等式 , 可以将其化为一个组合数. 代码: #include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdou

6445. 【GDOI2020模拟01.19】String

题目 正解 一听到正解是NTT,我心态崩了. 我特么知道是NTT都不知道该怎么做!哪里像个卷积了? 好吧,是我孤陋寡闻-- 设两个字符串分别为\(A\)和\(B\) 可以考虑试着计算出\(A\)每个子串和\(B\)的相似度(就是位置相同.字母相同的个数),直接统计就完事了. 看到字符集这么小,就可以对于每个字母分开考虑. 假如\(A_i=B_j\),那么以\(A_{i-j+1}\)开头的子串就有\(1\)的贡献. 这样一来,看起来就很像是个卷积了. 搞完之后将贡献加起来,统计即可. 总结 还是没

6447. 【GDOI2020模拟01.19】sort

题目 正解 这题一看也是不能写的题目-- 用个平衡树来维护. 平衡树维护的是一个\(Trie\)的序列.每个\(Trie\)表示这段区间中所有数都会排序一遍. 进行各种操作时,首先会将至多两个节点的\(Trie\)分裂.分裂\(Trie\)会新增\(O(\lg n)\)个节点. 然后将整段区间旋到一棵子树内,然后打标记.平衡树和\(Trie\)上都要打标记. 排序是时候将若干个\(Trie\)合并成一个. 由于这些\(Trie\)是带标记的,所以要将标记下传.\(Trie\)树上标记下传时,如果

6467. 【GDOI2020模拟02.09】西行寺无余涅槃(FWT的性质)

题目描述 题解 吼题 推荐博客:https://www.cnblogs.com/jz-597/p/12300760.html 最暴力的做法是把n个2^m的FWT乘起来,这样显然不行 先把pi,1~k异或上pi,1,把pi,1变为0,最后再把pi,1异或回去 考虑FWT(xor)的本质,tr(A)=(tr(A1)+tr(A2),tr(A1)-tr(A2)),倒着做可以发现只有变换的u和u+2^k(u&2^k=0)只有u+2^k--->u+2^k这一操作时才需要变号 要求FWT(A)i,就等于把

6461. 【GDOI2020模拟02.05】生成树(矩阵树及其扩展、二维拉格朗日插值)

题目描述 给定一张 N 个点,M 条边的无向图,边有红.绿.蓝三种颜色,分别用 1,2,3 表示. 求这张图有多少生成树,满足绿色边数量不超过 x,蓝色边数量不超过 y,答案对10^9 + 7 取模. 1 ≤ N ≤ 40,1 ≤ M ≤ 10^5,1 ≤ ci ≤ 3 行列式 定义矩阵A的行列式det(A)或|A| \(|A|=\sum_{排列p}{(-1)^{p的逆序对个数}\prod{A_{i,p[i]}}}\) 行列式的性质 (\(A\)的转置矩阵\(A^T\):把\(A\)的行列互换)