链接
http://codeforces.com/contest/1005/problem/D
我的做法
先对整个数列
直接贪心,从左往右切,如果发现以当前位置为结束点的某个子串的和模3等于
,就在这个数后面切
我记录一个数组
表示以上一次切的位置的后面一个数字为起始点,到这个位置有没有和为
的前缀,在记录当前前缀和,如果当前的前缀和存在,那说明可以切了,复杂度
这个算法我不知道怎么证明,但是看了出题人的题解之后明白了
出题人的做法
出出题人用
做,
表示前缀
的答案
枚举以当前元素为结尾的子串
,如果子串中数字和为
(
),则
,取个最大值
但显然
是单调不下降的,所以我只需要找到最大的
即可。所以再开一个
数组记录前缀和为0
的最大的
,记录前缀和
,每次转移就是
,然后更新
这个和我的算法不是一模一样吗?
代码
#include <cstdio>
#include <cstring>
#define maxn 200010
using namespace std;
char s[maxn];
int n, cnt, last, t;
bool exist[5];
int main()
{
int i, j;
scanf("%s",s+1);
n=strlen(s+1);
for(i=1;i<=n;i++)s[i]=(s[i]-48)%3;
exist[0]=1;
for(i=1;i<=n;i++)
{
t=(t+s[i])%3;
if(exist[t])
{
cnt++;
for(j=1;j<=2;j++)exist[j]=0;
t=0;
}
else exist[t]=1;
}
printf("%d",cnt);
return 0;
}