cf1005 Round#496 Div3-D【思维】

这篇博客探讨了一个C++编程问题,涉及序列分组,要求每组元素相加模3的余数相同,且不允许前导0。作者首先尝试了贪心策略,但发现会丢失一些可能的组合。然后,通过更细致的状态分析,提出了一个改进的解决方案,考虑了1位、2位和3位数的情况,并成功避免了错误。代码实现包括两种不同的思路。
摘要由CSDN通过智能技术生成

Date:2021.12.25

题意:一个序列,求最多分成多少份使得%3==的份数最多,求这个份数,注意每一份不能存在前导0
思路1:贪心想,遍历元素。
①如果单个元素%3余0,答案++。
②如果单个元素%3不余0,记录余数,每次记录余数加和,直到余数和%3余0或者遇到①时,答案++。【一个数%3余0 <=> 每位和%3余0】
代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5+10;
LL n,m,k,t,l,r;
LL a[N],b[N];
bool st[N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    string s;cin>>s;
    int r=0,res=0;
    for(int i=0;i<s.size();i++)
    {
        if((int)s[i]-'0'==0){res++;r=0;}
        else 
        {
            if((int)(s[i]-'0')%3==0) {res++;r=0;}
            else
            {
                r+=(int)(s[i]-'0')%3;
                if(r%3==0)
                {
                    res++;
                    r=0;
                }
            }
        }
    }
    cout<<res;
    return 0;
}

然而wa11,模拟一下不难想到为什么,因为可能存在多个元素%3的余数加和后仍不能%3余0,但其中间可能存在某几个子模块%3是余0的,上述做法无疑减少了答案数。
(本来我是想用dp转移一下状态,结果试了写一下不太会…
思路2:仔细看答案分布是有规律的,我们还是分情况讨论。
①如果1位数%3余0,答案++。
②如果是2位数:
(1)若2位数相加%3余0,答案++。
(2)若2位数相加%3不余0,这2位数%3分别只能是1 1或2 2。
③如果是3位数,有3位数的前提是2位数的和%3不余0,因此在②–(2)的基础上衍生出③。
(1)前2位是1 1,第3位为1:这3位能凑出%3余0,答案++。
(2)前2位是1 1,第3位是2:后2位能凑出%3余0,答案++。
(3)前2位是2 2,第3位是1:后2位能凑出%3余0,答案++。
(4)前2位是2 2,第3位是2:这3位能凑出%3余0,答案++。
由上,至多3位数相加%3==0,因此每次记录和与满足①、②–(1)、③的任一一个答案++。
代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5+10;
LL n,m,k,t,l,r;
LL a[N],b[N];
bool st[N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    string s;cin>>s;
    int r=0,res=0,cnt=0;
    for(int i=0;i<s.size();i++)
    {
        r+=(s[i]-'0');
        cnt++;
        if((s[i]-'0')%3==0||r%3==0||cnt==3)
        //①当前单个元素%3==0
        //②当前累加的和%3==0
        //③当前元素个数为3,说明前2个加和%3!=0,再加上第3个元素,这3个元素中一定存在%3==0的
        {
            res++;
            cnt=0;r=0;
        }
    }
    cout<<res;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值