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

本文介绍了一种解决CodeForces 1005D问题的有效算法。通过使用贪心策略和动态规划方法来确定最优切割点,实现对数列的高效处理。详细解释了作者与出题者的两种解决方案,并通过代码示例展示了具体实现。

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

链接

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

我的做法

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

出题人的做法

出出题人用 dp d p 做, z[i] z [ i ] 表示前缀 i i 的答案
枚举以当前元素为结尾的子串s[j,i],如果子串中数字和为 0 0 (mod3),则 z[i]=z[j1]+1 z [ i ] = z [ j − 1 ] + 1 ,取个最大值
但显然 z[i] z [ i ] 是单调不下降的,所以我只需要找到最大的 j j 即可。所以再开一个fin[0...3]数组记录前缀和为0 ...3 . . .3 的最大的 j j ,记录前缀和s[i],每次转移就是 z[i]=z[fin[s[i]]]+1 z [ i ] = z [ f i n [ s [ i ] ] ] + 1 ,然后更新 fin[] 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值