Codeforces Round 496 (Div. 3) 1005D - Polycarp and Div 3

链接

http://codeforces.com/contest/1005/problem/D

我的做法

先对整个数列 mod 3
直接贪心,从左往右切,如果发现以当前位置为结束点的某个子串的和模3等于 0 ,就在这个数后面切
我记录一个数组 a [ 0...2 ] 表示以上一次切的位置的后面一个数字为起始点,到这个位置有没有和为 a [ i ] 的前缀,在记录当前前缀和,如果当前的前缀和存在,那说明可以切了,复杂度 O ( n )
这个算法我不知道怎么证明,但是看了出题人的题解之后明白了

出题人的做法

出出题人用 d p 做, z [ i ] 表示前缀 i 的答案
枚举以当前元素为结尾的子串 s [ j , i ] ,如果子串中数字和为 0 ( mod 3 ),则 z [ i ] = z [ j 1 ] + 1 ,取个最大值
但显然 z [ i ] 是单调不下降的,所以我只需要找到最大的 j 即可。所以再开一个 f i n [ 0...3 ] 数组记录前缀和为0 . . .3 的最大的 j ,记录前缀和 s [ i ] ,每次转移就是 z [ i ] = z [ f i n [ s [ i ] ] ] + 1 ,然后更新 f i n [ ]
这个和我的算法不是一模一样吗?

代码

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

猜你喜欢

转载自blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/81006477
今日推荐