Meaningless Sequence(思维+二项式)

Meaningless Sequence

[link](Problem - D - Codeforces)

题意

给你n和c,求 ∑ i = 0 n a i \sum_{i=0}^na_i i=0nai

题解

首先对于任意一个 a i a_i ai,假设 i i i二进制表达中有 c n t cnt cnt个1那么他的值就是 c c n t c^{cnt} ccnt。因为数是连续到第 i i i个的,所以 i i i对应的而二进制表达中一定有 c n t − 1 cnt-1 cnt1 1 1 1可以通过 & \& &留下来,那么他的值就是 c × 二 进 制 有 c n t − 1 个 一 的 数 的 对 应 a j 的 值 c\times二进制有cnt-1个一的数的对应a_j的值 c×cnt1aj,递归看下去就得到了一开始的结论。

一个一个算出来肯定不行,考虑怎么一类一类的算出来。发现当某个数的二进制是满1的话 ∑ i = 0 x a i = = ( 1 + c ) n \sum_{i=0}^xa_i==(1+c)^n i=0xai==(1+c)n,n为x的二进制位数。因为相当于一共n位在n位取小于等于n个1的组合数再乘以对应的权重, C n 0 ∗ c 0 + C n 1 ∗ c 1 + . . . + C n n ∗ c n = ( 1 + c ) n C_{n}^{0}*c^0 +C_{n}^{1}*c^1+...+C_{n}^{n}*c^n=(1+c)^n Cn0c0+Cn1c1+...+Cnncn=(1+c)n。这样就知道二进制全是1的数的和的什么了。

假设我们知道了 101 101 101的和为 s u m sum sum,那么 1101 1101 1101的和可以拆成两部分来看,一部分是 000 − 111 的 和 000-111的和 000111可以通过上面推导直接求出,另一部分是 1000 − 1101 1000-1101 10001101,这部分相当于 000 − 101 000-101 000101每个数都在最前面多加了一个1,每多加一1就会对单个的数多乘一个c,因此这一部分的权重是 c × s u m c\times sum c×sum。我们知道了这一步的推导是正确的,所以从尾往头遍历每一个数,每遇到一位1就这样转移一下,最终就可以线性求出答案了。

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath> 
#include <stack>
#include <iomanip>
#include <deque> 
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1);
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k, c;
int a[N];
LL qmi(LL a, LL b, LL p) {
    LL res = 1;
    while (b) {
        if (b & 1) res = res * a % p;   
        a = a * a % p;
        b >>= 1;
    }
    return res;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    string str;
    cin >> str >> c;
    LL res = 1;
    for (int i = str.size() - 1, k = 0; i >= 0; i --, k ++ ) 
        if (str[i] == '1') res = (res * c + qmi(c + 1, k, mod)) % mod;
    cout << res << endl;
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值