【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]={1over (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("
")
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
", ans);
}
原文地址:https://www.cnblogs.com/coldchair/p/12337242.html