牛客Wannafly挑战赛15-数字串

文章转载自:xuanqis.com

题目链接:点击打开链接

来源:牛客网

题目描述:

一个只含数字的字符串,q次操作,每次操作将第i位数字改为x,每次操作后,统计长度在[l, r]之间且首数字大于尾数字的子串的个数。

输入描述:

第一行一个只含数字的字符串;
第二行3个整数q, l, r;
接下来q行,每行两个整数i, x。

输出描述:

输出q行,每行一个整数,表示长度在[l, r]之间且首数字大于尾数字的子串的个数。

思路:

首先根据各个数字建立树状数组,再算出最开始的时候有多少个满足要求的串,然后对于所有的改变操作,计算改变前的受该点影响的值的大小,然后改变该点的数字,再次计算该点所能影响的值,两个值的差值就是改变数字所变化的值,然后用原来的减去就是当前所需要的。
注:代码有参考http://www.mamicode.com/info-detail-2293519.html

代码:

#define ll long long
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<string>
using namespace std; 
const int maxn = 1e5+5;

char s[maxn];
int c[12][maxn];  //存放j前面所具有的i个数
int lowbit(int x) {return x&(-x);}  //lowbit函数
int len;
void update_plus(int num, int p){  //更新数据
    for(int i = p; i <= len; i += lowbit(i)){
        c[num][i]++;
    }     
}

void init(){  //一个个的更新c数组
    for(int i = 1; i <= len; i++){
        update_plus(s[i]-'0', i);
    } 
}

void update_sub(int num, int p){  //进行减少
    for(int i = p; i <= len; i += lowbit(i)){
        c[num][i]--;
    }
}

ll add(int x, int p){  //计算从1到p的x的个数
    ll sum = 0;
    for(int i = p; i >= 1; i -= lowbit(i)){
        sum += 1ll*c[x][i];
    }
    return sum;
}

ll calculate(int p, int l, int r){
    ll sum=0; 
    for(int j = 0; j <= 9; j++){ 
        int b = p+ r-1, a = p+l-1;
        if (a <= len && j < (s[p]-'0')) sum += 1ll*add(j, min(len, b))-1ll*add(j, a-1);
        a = p-r+1, b = p-l+1;
        a = max(a, 1);
        if (b >= 1 && j > (s[p]-'0')) sum += 1ll*add(j, b)-1ll*add(j, a-1);
    }
    return sum;
}
int main() {
    int q, l, r; 
    int p, x;
    //freopen("1.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    scanf("%s", s+1);  //输入数
    len = strlen(s+1);  //长度
    init();  //初始化
    scanf("%d%d%d",&q,&l,&r);  //输入操作数,最小最大长度
    ll ans = 0;
    for(int i = 1; i <= len; i++){
        for(int j = 0; j <= 9; j++){
            int b = i+r-1, a = i+l-1;  //这里a是当前位加l-1,b是当前位加r-1
            if (a <= len && j < (s[i]-'0')) //如果
                ans += 1ll*add(j, min(len, b))-1ll*add(j, a-1);  //b算的减去a算的
        }
    }  //此时ans已经是不修改的值了
    for(int i = 1; i <= q; i++){
        scanf("%d%d", &p, &x);  //输入位置和修改后的值
        ll sum = calculate(p,l,r);  //原先的
        update_sub(s[p]-'0', p);  //原值减少
        update_plus(x, p);  //现值增加
        s[p] = '0'+x;  //注意这里要更改,防止多次更改该值
        ll sum2= calculate(p,l,r); //现在的
        ans = ans-sum+sum2;
        printf("%lld\n", ans);
    }
    return 0;
}

全部评论

相关推荐

DKS233:(1)专业技能:Java8也太旧了,最少也要了解到JDK17吧,可以参考现在SpringBoot支持的Java最低版本,熟悉mysql基本理论具体指啥,是锁这种具体原理还是分库分表这些业务场景,spring这些专业词汇,大小写要写对(全篇简历都有这个问题,显得不严谨),熟悉使用框架进行业务开发就别写了,如果要写,起码要写到框架原理部分吧,比如aop,启动原理什么的,springcloud具体指哪些模块呢,写清楚,网关还是鉴权还是什么,“改造”没必要写吧,你直接说用springcloud开发的不就行了(2)项目经历:首先格式就有大问题,时间怎么能换行呢,调整一下,响应速度那个,如果指的是将部分数据从其他数据库转到redis的提升就别写了,因为这个不算难点,redis可以写写分布式这些,比如容灾怎么实现的,数据库同步怎么做的
点赞 评论 收藏
分享
06-27 12:54
已编辑
门头沟学院 Java
累了,讲讲我的大学经历吧,目前在家待业。我是一个二本院校软件工程专业。最开始选专业是觉得计算机感兴趣,所以选择了他。本人学习计算机是从大二暑假结束开始的,也就是大三开始。当时每天学习,我个人认为Java以及是我生活的一部分了,就这样持续学习了一年半,来到了大四上学期末,大概是在12月中旬,我终于找的到了一家上海中厂的实习,但我发现实习生的工作很枯燥,公司分配的活也不多,大多时间也是自己在自学。就这样我秋招末才找到实习。时间来到了3月中旬,公司说我可以转正,但是转正工资只有7000,不过很稳定,不加班,双休,因为要回学校参加答辩了,同时当时也是心高气傲,认为可以找到更好的,所以放弃了转正机会,回学校准备论文。准备论文期间就也没有投递简历。然后时间来到了5月中旬,这时春招基本也结束了,然后我开始投递简历,期间只是约到了几家下场面试。工资也只有6-7k,到现在我不知道该怎么办了。已经没有当初学习的心劲了,好累呀,但是又不知道该干什么去。在家就是打游戏,boss简历投一投。每天日重一次。26秋招都说是针对26届的人,25怎么办。我好绝望。要不要参加考公、考研、央国企这些的。有没有大佬可以帮帮我。为什么感觉别人找工作都是顺其自然的事情,我感觉自己每一步都在艰难追赶。八股文背了又忘背了又忘,我每次都花很长时间去理解他,可是现在感觉八股、项目都忘完了。真的已经没有力气再去学习了。图片是我的简历,有没有大哥可以指正一下,或者说我应该走哪条路,有点不想在找工作了。
码客明:太累了就休息一下兄弟,人生不会完蛋的
如果实习可以转正,你会不...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务