• [NOI Online 2021 提高组] 愤怒的小N


    一道偏结论的题。当 (n=2^{k+1})

    [sum_{i=0, ext{popcount}(i)equiv 0pmod 2}^{2^{k+1}-1}i^k=sum_{i=0, ext{popcount}(i)equiv 1pmod 2}^{2^{k+1}-1}i^k ]

    采用归纳法证明(后文为方便以 (=0/1) 表示 (equiv 0/1))。当 (k=0) 时,结论显然成立;

    (k>0) 时,欲证明结论,先移项:

    [sum_{i=0, ext{popcount}(i)=0}^{2^{k+1}-1}i^k-sum_{i=0, ext{popcount}(i)=1}^{2^{k+1}-1}i^k=0 ]

    对于前缀相同的二进制 ((cdots 0))((cdots 1)) 均出现,仅最低位不同,考虑这样枚举

    [sum_{i=0}^{2^k-1}c_i imes left((2i+1)^k-(2i)^k ight)=0 ]

    (c_i)(+1)(-1),取决于前缀 (i)1 的个数。不难发现 (c_i=(-1)^{ ext{popcount}(i)})

    所以得到:

    [sum_{i=0}^{2^k-1}(-1)^{ ext{popcount}(i)}left((2i+1)^k-(2i)^k ight)=0 ]

    展开得到:

    [sum_{i=0}^{2^k-1}(-1)^{ ext{popcount}(i)}sum_{j=0}^{k-1}{kchoose j}(2i)^j=0 ]

    对于 ( ext{popcount}(i)) 分组,就变成:

    [sum_{j=0}^{k-1}2^j{kchoose j}sum_{i=0, ext{popcount}(i)=0}^{2^k-1}i^j=sum_{j=0}^{k-1}2^j{kchoose j}sum_{i=0, ext{popcount}(i)=1}^{2^k-1}i^j (*) ]

    由归纳,当 (k'<k) 时:

    [sum_{i=0, ext{popcount(i)}=0}^{2^{k'+1}-1}i^{k'}=sum_{i=0, ext{popcount(i)}=1}^{2^{k'+1}-1}i^{k'} ]

    引理:

    [sum_{i=0, ext{popcount(i)}=0}^{t imes 2^{k'+1}-1}i^{k'}=sum_{i=0, ext{popcount(i)}=1}^{t imes 2^{k'+1}-1}i^{k'}, tin  ]

    证明引理,我们只需要证明下式:

    [sum_{i=t imes 2^{k'+1}, ext{popcount}(i)=0}^{(t+1) imes 2^{k'+1}-1}i^{k'}=sum_{i=t imes 2^{k'+1}, ext{popcount}(i)=1}^{(t+1) imes 2^{k'+1}-1}i^{k'} ]

    我们同样可以归纳,这里省略掉部分细节。改写一下:

    [sum_{i=0, ext{popcount}(i)=0}^{2^{k'+1}-1}(i+t imes 2^{k'+1})^{k'}=sum_{i=0, ext{popcount}(i)=1}^{2^{k'+1}-1}(i+t imes 2^{k'+1})^{k'} ]

    同样展开:

    [sum_{i=0, ext{popcount}(i)=0}^{2^{k'+1}-1}sum_{j=0}^{k'}{k'choose j}i^j(t imes 2^{k'+1})^{k'-j}=sum_{i=0, ext{popcount}(i)=1}^{2^{k'+1}-1}sum_{j=0}^{k'}{k'choose j}i^j(t imes 2^{k'+1})^{k'-j} ]

    [Rightarrowsum_{j=0}^{k'}(t imes 2^{k'+1})^{k'-j}{k'choose j}sum_{i=0, ext{popcount}(i)=0}^{2^{k'+1}-1}i^j=sum_{j=0}^{k'}(t imes 2^{k'+1})^{k'-j}{k'choose j}sum_{i=0, ext{popcount}(i)=1}^{2^{k'+1}-1}i^j ]

    由归纳假设每一项都相等,由此引理得证。

    由上,对比每一项,能直接得到 ((*)) 式成立。故结论成立

    推导过程中,我们甚至能知道

    [sum_{i=0, ext{popcount}(i)=0}^{t imes 2^{k+1}-1}i^k=sum_{i=0, ext{popcount}(i)=1}^{t imes 2^{k+1}-1}i^k ]

    成立。这样我们就可以将复杂度从 (mathcal O(log_2 nk^2)) 降成 (mathcal O(k^3+..)) 了。

    #include <bits/stdc++.h>
    const int N = 500005, K = 505, P = 1e9 + 7, inv2 = P + 1 >> 1;
    int n, m, l, a[K], b[N], c[N], ans = 0; char str[N];
    int inv[K], fac[K], ifac[K], pw[K], f0[K], f1[K], g0[K], g1[K], y[K];
    int C(int n, int m) { return 1LL * fac[n] * ifac[m] % P * ifac[n - m] % P; }
    int lagrange(int n, int k) {
    	for (int i = 0; i <= k + 1; i++) {
    	    y[i] = 1;
    		for (int j = 1; j <= k; j++)
    			y[i] = 1LL * y[i] * i % P;
    		if (i) y[i] = (y[i] + y[i - 1]) % P;
    	}
    	int ans = 0;
    	for (int i = 0; i <= k + 1; i++) {
    		int tmp = y[i];
    		for (int j = 0; j <= k + 1; j++)
    			if (i != j) tmp = 1LL * tmp * (n - j + P) % P * (i > j ? inv[i - j] : P - inv[j - i]) % P;
    		ans = (ans + tmp) % P;
    	}
    	return ans;
    }
    int main() {
    	scanf("%s%d", str, &m);
    	for (int i = 0; i < m; i++) scanf("%d", &a[i]);
    	n = strlen(str); l = std::min(n, m);
    	std::reverse(str, str + n);
    	for (int i = n - 1; ~i; i--)
    		b[i] = (2 * b[i + 1] + (str[i] == '1')) % P, c[i] = c[i + 1] ^ (str[i] == '1');
    	inv[1] = 1;
    	for (int i = 2; i <= m; i++) inv[i] = 1LL * (P - P / i) * inv[P % i] % P;
    	fac[0] = ifac[0] = pw[0] = 1;
    	for (int i = 1; i <= m; i++)
    		fac[i] = 1LL * fac[i - 1] * i % P, ifac[i] = 1LL * ifac[i - 1] * inv[i] % P, pw[i] = 2 * pw[i - 1] % P;
    	f0[0] = 1;
    	for (int i = 0; i < l; i++) {
    		if (str[i] == '1') {
    			int x = 1LL * b[i + 1] * pw[i + 1] % P;
    			for (int j = i; j < m; j++)
    				for (int k = 0, t = a[j]; k <= j; k++)
    					ans = (ans + 1LL * C(j, k) * t % P * (c[i] ? f1[j - k] : f0[j - k])) % P, t = 1LL * t * x % P;
    		}
    		for (int j = 0; j < m; j++) {
    			g0[j] = g1[j] = 0;
    			for (int k = j; ~k; k--)
    			    g0[j] = (g0[j] * 2 + 1LL * C(j, k) * f1[k]) % P,
    			    g1[j] = (g1[j] * 2 + 1LL * C(j, k) * f0[k]) % P;
    		}
    		for (int j = 0; j < m; j++)
    			f0[j] = (1LL * f0[j] * pw[j] + g0[j]) % P, f1[j] = (1LL * f1[j] * pw[j] + g1[j]) % P;
    	}
    	for (int i = 0; i < m; i++)
    		ans = (ans + 1LL * a[i] * lagrange(1LL * b[i + 1] * pw[i + 1] % P - 1, i) % P * inv2) % P;
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    关于Android的nodpi,xhdpi,hdpi,mdpi,ldpi
    在android上监听网络状态的变更
    mysql:insert on duplicate key 版本导致问题
    android中TextView中文字体粗体的方法
    10.2香港一人一日购物游流水账
    结婚的意义
    关于摄影的若干个命题
    人生若彷如倒序。。。本杰明·巴顿奇事 The Curious Case of Benjamin Button
    阳光十六法则
    花街人真多,多我一个就溢出了
  • 原文地址:https://www.cnblogs.com/ac-evil/p/14588823.html
Copyright © 2020-2023  润新知