2019牛客暑期多校训练营(第四场) K题 number

本文介绍一种高效算法,用于计算字符串中所有300的倍数子串的数量,通过分解条件判断,简化计算过程。文章提供了一个C++实现示例,详细解释了如何利用前缀和思想解决此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述
300iq loves numbers who are multiple of 300.
One day he got a string consisted of numbers. He wants to know how many substrings in the string are multiples of 300 when considered as decimal integers.
Note that leading and trailing zeros are allowed (both in original string and substrings you chose) and the same substring appearing in different places can be counted multiple times.
输入描述:
A single line consisting a string consisted of characters ‘0’ to ‘9’.
输出描述:
The number of substrings that are multiples of 300 when considered as decimal integers.
示例1
输入

600
输出

4
说明
‘600’, ‘0’, ‘0’, ‘00’ are multiples of 300. (Note that ‘0’ are counted twice because it appeared two times)
示例2
输入

123000321013200987000789
输出

55
备注:
let the string in the input be s, 1≤∣s∣≤10510^5105
.
分析:
让求的是300的倍数,但是呢我们可以拆成既是3的倍数也是100的倍数
那么这样就可以找到一些规律:
1.对于3的倍数来说就是各个位上的数值加起来和对3取余答案是0
2.对于100的倍数来说就是要求后两位至少为0
有了这个规律之后就完成了一半,还有一半就是这个:
大家可以注意到两个相同余数之间都是算作答案里面的,这句话是是什么意思呢????
举个栗子:
假设给出的整数是:
1 0 1 0 0 1 2 0 0 0
对3取余的结果:1 1 2 2 2 0 2 2 2 2
对于下面“对3取余的结果”是求前缀和才得到的,大家在去理解一下,什么叫“两个相同余数之间”
拿上面的例子,取余结果为2的区间是 1 0 0 1 2 是这个区间
有人会问,为甚不包括后面的三个0呢,因为第一次遇到两个连续的0,就是我们更新答案的地方,必须到这个地方停下来
此时取余为2的个数为4(2 2 2 0 2,4个2),那么这个区间就是下面这个五个答案:
001200 01200 1200 00
又要有人问,为甚没有后面两个0 0,这样就是7个了,因为单个0我们一开始就需要特殊处理一下
下面结合代码便于理解

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstring>
#include<set>
#include<queue>
#include<stack>
#include<map>
using namespace std;
const int N=1e5+10;
char str[N];
typedef long long ll;
ll ans=0, cnt[N];

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    scanf("%s",str);
    cnt[0]=1;
    int len=strlen(str);
    for(int i=0;i<len;i++){
        if(str[i]=='0')
            ans++;//先处理单个0的情况
    }
    int sum=0;
    for(int i=0;i<len-1;i++){
        sum+=str[i]-'0';
        sum%=3;
        if(str[i]=='0' && str[i+1]=='0')
            ans+=cnt[sum];
        cnt[sum]++;
    }
    printf("%lld\n",ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值