Codeforces ~ 1062C ~ Math(贪心,前缀和,快速幂)

在这里插入图片描述

在这里插入图片描述

题意

给你一个长度为n的01串,q次询问,每次询问[l,r]区间可以获得的最大值为多少,取模1e9+7。
假定答案为ans,ans初始为0。你每次选择01串中的某个元素将其吃掉,ans加上这个元素的值,并将其他元素都加上这个元素的值。
比如第一个样例的第一次询问,串的变化过程如下:
“1011”,“x122”,“x34x”,“x7xx”,“xxxx”,
ans = 1+2+4+7

思路

容易发现每次吃最大的那个值更优。推几个样例可以发现:
对于一个k个1的序列,可以发现ans增加过程为 1 + 2 + 4 + 8 + 16 + . . . + 2 k − 1 = 2 k − 1 1+2+4+8+16+...+2^{k-1}=2^k-1 1+2+4+8+16+...+2k1=2k1
对于一个k个1,z个0的序列,那么ans增加过程为
2 0 + 2 1 + . . + 2 k − 1 + ( 2 k − 2 0 ) + ( 2 k + 1 − 2 1 ) + ( 2 k + 2 − 2 2 ) + . . . + ( 2 k + z − 1 − 2 z − 1 ) = ( 2 k + z − 1 ) − ( 2 z − 1 ) 2^0+2^1+..+2^{k-1}+(2^{k}-2^0)+(2^{k+1}-2^1)+(2^{k+2}-2^2)+...+(2^{k+z-1}-2^{z-1})=(2^{k+z}-1)-(2^z-1) 20+21+..+2k1+(2k20)+(2k+121)+(2k+222)+...+(2k+z12z1)=(2k+z1)(2z1)
所以答案就是 2 l e n − 2 z r e o 2^{len}-2^{zreo} 2len2zreo
区间内1的个数用前缀和求一下就好了。
注意因为取模,所以 2 l e n − 2 z r e o 2^{len}-2^{zreo} 2len2zreo可能是负数,要变为正数。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+5;
typedef long long LL;
const int MOD = 1e9+7;
int n, q, a[MAXN];
char s[MAXN];
LL qpow(LL a, LL b)
{
    LL res = 1;
    while (b)
    {
        if (b&1) res = res*a%MOD;
        a = a*a%MOD;
        b >>= 1;
    }
    return res;
}
int main()
{
    scanf("%d%d%*c%s", &n, &q, s+1);
    for (int i = 1; i <= n; i++) a[i] = s[i]-'0'+a[i-1];
    while (q--)
    {
        int l, r; scanf("%d%d", &l, &r);
        LL ans = qpow(2, r-l+1)-qpow(2, (r-l+1)-(a[r]-a[l-1]));
        printf("%lld\n", (ans+MOD)%MOD);
    }
    return 0;
}
/*
4 2
1011
1 4
3 4
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值