【GDOI2020模拟02.19】A (数位dp+范德蒙恒等式)

\(n<=12,d<=500,l,r<=d^{500}\)

题解:

解法1:

使r-=l,并把所有l相加。

这样只用考虑与r的关系。

\(f[i][S][j=0-n]\)表示确定了高位的i位,与r的数位关系的状态是S,需要低位进j为上来。

转移可以枚举S,再枚举S'∈S,做n次前缀和确定这一位系数,再转移。

复杂度:\(O(d*3^n*n^2*d)\)

也可以用高维前缀和优化这个转移,设\(g[i][S][j][k]\)表示确定了S的前i位,现在是S,需要进j位,现在和是k,初值通过f得来。

复杂度:\(O(d*2^n*n^4*d)\)

解法2:

前面的都是考虑<=r,这也是数位dp的常规做法。

现在考虑容斥>l。

\(s=\sum l\),如果最后的和是\(v\),那么系数就是挡板问题:\(C_{v-s-1}^{n-1}\)

范德蒙恒等式:\(C_{n+m}^k=\sum_{i=0}^kC_{n}^i*C_{m}^{k-i}\)

当n、m、k是非负数的时候显然成立,其实n,m是负数时也成立,可以用生成函数解释。

那么把\(C_{v-s-1}^{n-1}\)拆开,\(=\sum_{i=0}^{n-1}C_{v}^i*C_{-s-1}^{n-1-i}\)

下标为负的组合数的求法:
\(C_{-n}^m=(-n)^{m↓}/m!\)

或者\((1+x)^{-n}[x^m]={1\over (1+x)^n}[x^m]\)

只需要求出\(C_v^i*[v d进制下每个数位都出现在T中]*[v>s]\)的和即可。

那么还是数位dp,设\(f[i][0/1][j]\)表示确定了高位的i位,与s的数位关系,\(C_{v}^i\)的和。

转移时相当于求\(C_{v+d^i*num}^i\)同样可以代入范德蒙恒等式拆开。

我把组合数展开成下降幂,然后维护0~n次和,是差不多的。

注意下前导0的处理,可以dp多开一维,这样太慢了,不如每次手工加回前导零的系数。

时间复杂度:\(O(2^n*d*n^2)\)

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int mo = 1e9 + 7;

ll ksm(ll x, ll y) {
    ll s = 1;
    for(; y; y /= 2, x = x * x % mo)
        if(y & 1) s = s * x % mo;
    return s;
}

const int N = 510;


int n, d, ky[N];

struct P {
    int a0, a[N];
    P() {
        a0 = 0; memset(a, 0, sizeof a);
    }
};

P operator + (P a, P b) {
    a.a0 = max(a.a0, b.a0);
    fo(i, 0, a.a0) {
        a.a[i] += b.a[i];
        if(a.a[i] >= d) a.a[i + 1] ++, a.a[i] -= d;
    }
    while(a.a[a.a0 + 1]) a.a0 ++;
    return a;
}

P operator - (P a, P b) {
    a.a0 = max(a.a0, b.a0);
    fo(i, 0, a.a0) {
        a.a[i] -= b.a[i];
        if(a.a[i] < 0) a.a[i] += d, a.a[i + 1] --;
    }
    while(a.a0 > 0 && !a.a[a.a0]) a.a0 --;
    return a;
}

namespace read {
char str[N * 3];
int b[N * 3];
void read(P &a) {
    memset(b, 0, sizeof b);
    int n;
    scanf("%s", str + 1);
    n = strlen(str + 1);
    fo(i, 1, n) b[i] = str[n - i + 1] - '0';
    a.a0 = -1;
    while(n > 1 || b[n] > 0) {
        int y = 0;
        fd(i, n, 1) {
            b[i] += y * 10;
            y = b[i] % d; b[i] /= d;
        }
        while(n > 0 && !b[n]) n --;
        a.a[++ a.a0] = y;
    }
}
}

void write(P a) {
    fo(i, 0, a.a0) pp("%d ", a.a[i]); hh;
}

P l[15], r[15], sum, val_1;

int mx;

ll c[15][15], fac[15], nf[15];

void build(int n) {
    fo(i, 0, n) {
        c[i][0] = 1;
        fo(j, 1, i) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mo;
    }
    fac[0] = nf[0] = 1;
    fo(i, 1, n) fac[i] = fac[i - 1] * i % mo, nf[i] = ksm(fac[i], mo - 2);
}

struct Q {
    ll x, y;
};
ll ad[N]; Q ax[N][N][15];

ll f[2][2][13]; int o;

ll cnt[15], cnt2[15], cnt3[15];

ll p[15];

ll ans;

void dp(P sum, int xs) {
    memset(f, 0, sizeof f);
    f[o][1][0] = 1;
    int q0 = 1;
    fd(w, mx + 5, 0) {
        int num = sum.a[w];
        if(num) q0 = 0;
        o = !o; memset(f[o], 0, sizeof f[o]);
        ff(i, 0, n) ff(j, i, n) {
            f[o][0][j] += f[!o][0][i] * c[j][i] % mo * ax[w][d - 1][j - i].y % mo;
            f[o][0][j] += f[!o][1][i] * c[j][i] % mo * (ax[w][d - 1][j - i].y - ax[w][num][j - i].y) % mo;
            f[o][1][j] += f[!o][1][i] * c[j][i] % mo * ax[w][num][j - i].x % mo;
        }
        if(q0 && !ky[0]) f[o][1][0] ++;
        fo(i, 0, n) f[o][0][i] %= mo, f[o][1][i] %= mo;
    }
    ff(i, 0, n) cnt[i] = (f[o][0][i] + f[o][1][i]) % mo;
    memset(p, 0, sizeof p);
    p[0] = 1; cnt2[0] = cnt[0];
    ff(i, 1, n) {
        fd(j, i, 0) p[j] = (p[j] * -(i - 1) + (j ? p[j - 1] : 0)) % mo;
        cnt2[i] = 0; fo(j, 0, i) cnt2[i] = (cnt2[i] + cnt[j] * p[j]) % mo;
        cnt2[i] = cnt2[i] * nf[i] % mo;
    }
    ll s = 0;
    fo(i, 0, sum.a0) s = (s + ad[i] * sum.a[i]) % mo;
    cnt3[0] = 1;
    ff(i, 1, n) cnt3[i] = cnt3[i - 1] * (-s - (i - 1)) % mo;
    ff(i, 1, n) cnt3[i] = cnt3[i] * nf[i] % mo;
    fo(i, 0, n - 1) ans = (ans + cnt2[i] * cnt3[n - 1 - i] % mo * xs) % mo;
}

void dg(int x, P s, int xs) {
    if(x > n) {
        dp(s, xs);
        return;
    }
    dg(x + 1, s + l[x], xs);
    dg(x + 1, s + r[x], -xs);
}

int main() {
    freopen("A.in", "r", stdin);
    freopen("A.out", "w", stdout);
    scanf("%d %d", &n, &d);
    build(n);
    ff(i, 0, d) scanf("%d", &ky[i]);
    val_1.a[0] = 1;
    fo(i, 1, n) {
        read :: read(l[i]);
        read :: read(r[i]);
        mx = max(mx, r[i].a0);
        l[i] = l[i] - val_1;
    }
    ad[0] = 1; fo(i, 1, mx + 5) ad[i] = ad[i - 1] * d % mo;
    fo(i, 0, mx + 5) {
        fo(j, 0, d - 1) fo(k, 0, n) {
            ax[i][j][k].x = ksm(j * ad[i] % mo, k);
            if(!ky[j]) ax[i][j][k].x = 0;
            ax[i][j][k].y = ((j ? ax[i][j - 1][k].y : 0) + ax[i][j][k].x) % mo;
        }
    }
    dg(1, val_1, 1);
    ans = (ans % mo + mo) % mo;
    pp("%lld\n", ans);
}

猜你喜欢

转载自www.cnblogs.com/coldchair/p/12337242.html
今日推荐