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;
}