传送门


问题等价于从 20a1,21a1,,259a1,20a2,,259an2^0\cdot a_1, 2^1\cdot a_1, \cdots, 2^{59}\cdot a_1, 2^0\cdot a_2, \cdots, 2^{59}\cdot a_n60n60n 个物品中,扣除所有 2ciabi2^{c_i}\cdot a_{b_i}kk 个物品后,查询体积不超过 mm 的背包方案数

注意到每个 aia_i 前面乘的系数都是 22 的整幂次,若我们对进行背包的物品,按系数的 22 的幂次进行分类,从小到大进行背包;则在 2t2^t 为系数的物品进行背包后,后续物品再次进行背包,是不可能影响低于 tt 位的二进制数码的

为了避免状态过多,我们试图采用数位 dp 的方式,一位一位考虑对答案的贡献

注意到若进行到第 tt 位后,若体积 VV 的二进制低 tt 位大于 mm ,即 Vmod2t>mmod2tV\bmod 2^t>m\bmod 2^t ,则当且仅当 VV 的第 t+1t+1 位为 00mm 的第 t+1t+1 位为 11 会使得 Vmod2t+1mmod2t+1V\bmod 2^{t+1}\leq m\bmod 2^{t+1} ;若体积 VV 的二进制低 tt 位小于等于 mm ,即 Vmod2tmmod2tV\bmod 2^t\leq m\bmod 2^t ,则当且仅当 VV 的第 t+1t+1 位为 11mm 的第 t+1t+1 位为 00 会使得 Vmod2t+1>mmod2t+1V\bmod 2^{t+1}> m\bmod 2^{t+1}

因此,我们考虑记 dpt,i,0/1dp_{t, i, 0/1} 表示进行完 2t2^t 为系数的物品的背包后,体积 VV 满足 V2t+1=i\lfloor{V\over 2^{t+1}}\rfloor=i ,且 Vmod2t+1V\bmod 2^{t+1} 是否严格大于 mmod2t+1m\bmod 2^{t+1} ,的方案数

故答案是 i=1naixim\displaystyle \sum_{i=1}^n a_ix_i\leq m ,即是 VmV\leq m 的方案数。由于 m<260m<2^{60} ,故 0V259+1m259+1<1,Vmod259+1mmod259+10\leq \lfloor{V\over 2^{59+1}}\rfloor\leq \lfloor{m\over 2^{59+1}}\rfloor<1, V\bmod 2^{59+1}\leq m\bmod 2^{59+1} ,因此答案为 dp59,0,0dp_{59, 0, 0}

这种情况下,0t59,0iV2t12tx=0ti=1n2xai=i=1nai12tx=0t2x2i=1nai:=2A\displaystyle 0\leq t\leq 59, 0\leq i\leq \lfloor{V\over 2^t}\rfloor \leq {1\over 2^t}\sum_{x=0}^t\sum_{i=1}^n 2^x\cdot a_i=\sum_{i=1}^n a_i\cdot {1\over 2^t}\sum_{x=0}^t 2^x\leq 2\sum_{i=1}^n a_i:=2A


考虑该 dpdp 的转移,首先,我们需要知道系数为 2t2^t 的物品的背包结果,它可以用生成函数 i=1(i,t)∉{(bk,ck)}n(1+x2tai)\displaystyle \prod_{i=1\\(i, t)\not\in \{(b_k, c_k)\}}^n (1+x^{2^t\cdot a_i}) ,我们记为 gt(x2t)g_t(x^{2^t}) ,即 gt(x)=i=1(i,t)∉{(bk,ck)}n(1+xai)=i=1n(1+xai)[(i,t){(bk,ck)}(1+xai)]1\displaystyle g_t(x)=\prod_{i=1\\(i, t)\not\in \{(b_k, c_k)\}}^n (1+x^{a_i})=\prod_{i=1}^n(1+x^{a_i})\cdot [\prod_{(i, t)\in \{(b_k, c_k)\}} (1+x^{a_i})]^{-1}

我们可以先用多项式线段树分治或多项式启发式合并,先在 O(n2n)O(n\log^2 n) 的时间内求出 g(x)=i=1n(1+xai)\displaystyle g(x)=\prod_{i=1}^n(1+x^{a_i}) 。后续求解 gt(x)g_t(x) 时,只需要反向跑背包进行删除,复杂度为 O(n)O(n) ;由于限制数量为 k5×103k\leq 5\times 10^3 个,故复杂度 O(kn)O(kn) 是可接受的

现在考虑已知 dpt1,0,2A,0/1dp_{t-1, 0\cdots, 2A,0/1} 、已知 [xl]gt(x)[x^l]g_t(x) ,如何合并得出 dpt,02A,0/1dp_{t, 0\cdots 2A, 0/1} 的结果

由于 dpt1,i,0dp_{t-1, i, 0} 表示进行完 2t12^{t-1} 为系数的物品后,体积 VV 满足 V2t=i\lfloor{V\over 2^t}\rfloor=i ,且 Vmod2tmmod2tV\bmod 2^t\leq m\bmod 2^t 的方案数;[xl]g(x)[x^l]g(x) 表示系数为 2t2^t 的物品,拼出体积为 2tl2^t\cdot l 的方案数

因此将两者合并后,新体积 V=V+2tlV2t+1=V+2tl2t+1=i+l2\displaystyle V'=V+2^t\cdot l\Rightarrow \lfloor{V'\over 2^{t+1}}\rfloor=\lfloor{V+2^t\cdot l\over 2^{t+1}}\rfloor=\lfloor{i+l\over 2}\rfloor ,大小关系 b=[Vmod2t+1>mmod2t+1]=[Vt>mt]=[V2t0>mt]=[(i+l)mod2>mt]\displaystyle b=[V'\bmod 2^{t+1}>m\bmod 2^{t+1}]=[V'_t>m_t]=[\lfloor{V'\over 2^t}\rfloor_0>m_t]=[(i+l)\bmod 2>m_t]

于是可以写出一部分的转移式:dpt,I2,[Imod2>mt]=i+l=Idpt1,i,0[xl]gt(x)\displaystyle dp_{t, \lfloor{I\over 2}\rfloor, [I\bmod 2>m_t]}=\sum_{i+l=I}dp_{t-1, i, 0}\cdot [x^l]g_t(x) ,显然是加法卷积的形式,可以在 O(2Alog2A)O(2A\log 2A) 的时间内求解

同理,另一部分转移式为:dpt,I2,[Imod2mt]=i+l=Idpt1,i,1[xl]gt(x)\displaystyle dp_{t, \lfloor{I\over 2}\rfloor, [I\bmod 2\geq m_t]}=\sum_{i+l=I}dp_{t-1, i, 1}\cdot [x^l]g_t(x) ,同样是加法卷积,可以在 O(2Alog2A)O(2A\log 2A) 的时间内求解

初始时,是 dp0,i,0/1dp_{0, i, 0/1} 表示进行完 202^0 为系数的物品后,体积 V2=i\lfloor{V\over 2}\rfloor=iVmod2V\bmod 2 是否严格大于 mmod2m\bmod 2 ;也是直接由 [xl]g0(x)[x^l]g_0(x) 贡献到 dp0,l2,lmod2>mmod2dp_{0, \lfloor{l\over 2}\rfloor, l\bmod 2>m\bmod 2}


综上,先对 (1+xai)(1+x^{a_i}) 进行 O(n2n)O(n\log^2 n) 的多项式启发式合并或多项式线段树分治;接着对数位进行 DP,先求出 gt(x)g_t(x) ,再分别利用 dpt1,02A,0,dpt1,02A,1dp_{t-1, 0\cdots 2A, 0},dp_{t-1, 0\cdots 2A, 1}gt(x)g_t(x) 卷积递推 dpt,02A,0/1dp_{t, 0\cdots 2A, 0/1} 的贡献

gt(x)g_t(x) 的总复杂度为 O(nk)O(nk) ,卷积递推的复杂度为 O(logm22Alog2A)=O(logmAlogA)=O(logmnlogn)O(\log m\cdot 2\cdot 2A\log 2A)=O(\log m\cdot A\log A)=O(\log m\cdot n\log n)

故总复杂度为 O(nlogn(logn+logm)+nk)O(n\log n(\log n+\log m)+nk)


【核心代码】

const int Lim=8e4, MAXN=Lim+10;
int n, k, a[MAXN];
ll m, mask[MAXN];
poly f, g, h;
inline void divit(poly &f, int a) {
	for(int i=sz(f)-1, j=i-a; j>=0; --i, --j)
		f[j]=f[j]-f[i];
	for(int i=0, j=a, J=sz(f); j<J; ++i, ++j)
		f[i]=f[j];
	rsz(f, sz(f)-a);
}

vir dp[2][MAXN][2];
inline void work() {
	g=f;
	for(int i=1; i<=n; ++i) if(mask[i]&1) divit(g, a[i]);
	for(int i=sz(g)-1; ~i; --i) dp[0][i>>1][(i&1)>(m&1)]=dp[0][i>>1][(i&1)>(m&1)]+g[i];
	
	for(int t=1; t<=59; ++t) {
		auto lst=dp[t+1&1], now=dp[t&1];
		int mt=(m>>t)&1;
		for(int i=0, I=Lim; i<=I; ++i) now[i][0]=now[i][1]=0;
		g=f;
		for(int i=1; i<=n; ++i) if((mask[i]>>t)&1) divit(g, a[i]);
		
		rsz(h, Lim+1);
		for(int i=0; i<=Lim; ++i) h[i]=lst[i][0];
		Poly::get_mul(h, g, sz(h), sz(g));
		for(int i=sz(h)-1; ~i; --i)
			now[i>>1][(i&1)>mt]=now[i>>1][(i&1)>mt]+h[i];
		rsz(h, Lim+1);
		for(int i=0; i<=Lim; ++i) h[i]=lst[i][1];
		Poly::get_mul(h, g, sz(h), sz(g));
		for(int i=sz(h)-1; ~i; --i)
			now[i>>1][(i&1)>=mt]=now[i>>1][(i&1)>=mt]+h[i];
	}
	
	cout<<(int)dp[1][0][0];
}
inline void init() {
	Poly::init();
	cin>>n>>m>>k;
	for(int i=1; i<=n; ++i) {
		cin>>a[i];
		poly &p=Poly::T[i];
		rsz(p, a[i]+1);
		p[0]=p[a[i]]=1;
	}
	f=Poly::get_merge(n);
	
	for(int i=1, x, y; i<=k; ++i)
		cin>>x>>y, mask[x]|=pw(y);
}