题意
给你一个长度为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+...+2k−1=2k−1
对于一个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+..+2k−1+(2k−20)+(2k+1−21)+(2k+2−22)+...+(2k+z−1−2z−1)=(2k+z−1)−(2z−1)
所以答案就是
2
l
e
n
−
2
z
r
e
o
2^{len}-2^{zreo}
2len−2zreo
区间内1的个数用前缀和求一下就好了。
注意因为取模,所以
2
l
e
n
−
2
z
r
e
o
2^{len}-2^{zreo}
2len−2zreo可能是负数,要变为正数。
#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
*/