zoukankan      html  css  js  c++  java
  • 【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);
    }
    
  • 相关阅读:
    032 Gradle 下载的依赖jar包在哪?
    031 can't rename root module,Android Studio修改项目名称
    030 Cannot resolve symbol'R' 问题解决汇总大全
    029 Android Studio层级显示目录文件
    028 You are about to commit CRLF line separators to the Git repository.It is recommended to set the core. autocrlf Git attribute to true to avoid line separator issues If you choose Fix and Comit ,
    027 【Android基础知识】Android Studio 编译慢及 Adb connection Error:远程主机强迫关闭了一个现有的连接
    026 Android Studio 和Gradle版版本对应关系
    025 Cause: org.jetbrains.plugins.gradle.tooling.util.ModuleComponentIdentifierIm
    024 Android Studio上传项目到Github 最全记录
    023 解决AndroidStudio下载gradle慢的问题
  • 原文地址:https://www.cnblogs.com/coldchair/p/12337242.html
Copyright © 2011-2022 走看看