【Codeforces Round #520 C.Banh-mi】前缀和+快速幂

35 篇文章 1 订阅
24 篇文章 0 订阅

C. Banh-mi

题意

题 意 就 是 给 你 一 个 01 串 , q 次 询 问 每 次 询 问 一 段 区 间 题意就是给你一个01串,q次询问每次询问一段区间 01q
每 次 询 问 询 问 的 是 : 最 初 区 间 内 0 的 权 值 是 0 , 1 的 权 值 是 1 每次询问询问的是:最初区间内0的权值是0,1的权值是1 0011
每 次 可 以 移 出 一 个 字 符 , 移 除 后 答 案 加 上 该 字 符 的 权 值 每次可以移出一个字符,移除后答案加上该字符的权值
其 余 所 有 字 符 加 上 该 字 符 的 权 值 其余所有字符加上该字符的权值
最 后 询 问 每 个 区 间 内 能 获 得 的 最 大 答 案 , 每 次 查 询 是 独 立 的 最后询问每个区间内能获得的最大答案,每次查询是独立的

做法

首 先 我 们 发 现 , 对 每 个 区 间 来 说 , 一 定 是 一 直 拿 1 , 1 没 有 了 拿 0 这 个 策 略 首先我们发现,对每个区间来说,一定是一直拿1,1没有了拿0这个策略 110
所 以 问 题 就 变 为 给 你 一 个 先 1 后 0 的 序 列 来 计 算 上 面 的 问 题 所以问题就变为给你一个先1后0的序列来计算上面的问题 10
而 这 个 序 列 中 0 , 1 的 个 数 我 们 都 可 以 通 过 前 缀 和 快 速 计 算 出 来 而这个序列中0,1的个数我们都可以通过前缀和快速计算出来 01
我 们 发 现 对 于 每 个 1 的 区 间 , 对 答 案 的 贡 献 是 一 段 首 项 为 1 我们发现对于每个1的区间,对答案的贡献是一段首项为1 11
公 比 为 2 , 长 度 为 1 的 个 数 等 比 数 列 公比为2,长度为1的个数等比数列 21
对 于 每 个 0 的 区 间 , 对 答 案 的 贡 献 是 一 段 首 项 为 1 那 段 区 间 对 答 案 的 贡 献 对于每个0的区间,对答案的贡献是一段首项为1那段区间对答案的贡献 01
公 比 为 2 , 长 度 为 0 的 个 数 的 等 比 数 列 公比为2,长度为0的个数的等比数列 20
之 后 加 个 快 速 幂 再 加 个 前 缀 和 预 处 理 这 道 题 就 做 完 了 “ ” 之后加个快速幂再加个前缀和预处理这道题就做完了“”

坑点

有 减 法 要 加 M o d 有减法要加Mod%Mod Mod

代码

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<map>
#include<bitset>
#include<stack>
#include<set>
#include<vector>
#include <time.h>
#include<string.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <ll, int> pli;
typedef pair <db, db> pdd;

const int maxn = 1e5+5;
const int Mod=1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const double e=exp(1);
const db PI = acos(-1);
const db ERR = 1e-10;

#define Se second
#define Fi first
#define pb push_back
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl
ll pow_(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=(ans*a)%Mod;
        b>>=1;
        a=(a*a)%Mod;
    }
    return ans;
}
ll inv(ll x)
{
    return pow_(x,Mod-2);
}
ll sum[maxn][2];
char str[maxn];
int main()
{
    //ios::sync_with_stdio(false);
    //freopen("a.txt","r",stdin);
    //freopen("b.txt","w",stdout);
    int n,q;
    scanf("%d%d",&n,&q);
    scanf("%s",str+1);
    for(int i=1;i<=n;i++)
    {
        sum[i][0]=sum[i-1][0];
        sum[i][1]=sum[i-1][1];
        if(str[i]=='0') sum[i][0]=(sum[i][0]+1)%Mod;
        else sum[i][1]=(sum[i][1]+1)%Mod;;
    }
    while(q--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        ll sum0=(sum[r][0]-sum[l-1][0]+Mod)%Mod;
        ll sum1=(sum[r][1]-sum[l-1][1]+Mod)%Mod;
        ll ans=0;
        ans=(pow_(2,sum1)-1+Mod)%Mod;
        ll st=(pow_(2,sum1)-1+Mod)%Mod;
        ll tmp=(pow_(2,sum0)-1+Mod)%Mod;
        tmp=(tmp*st)%Mod;
        ans=(ans+tmp)%Mod;
        printf("%lld\n",ans);
    }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值