noi.ac 34 洛谷 4656 libreoj 2484 [CEOI2017]Palindromic Partitions

博客观赏效果更佳
(noi.ac题面被改过了,题意是一样的)

题意简述

给你一个字符串 S S S,长度 1 e 6 1e6 1e6
S S S的一个 k k k个串的划分 a 1 , a 2 . . . a k a_1,a_2...a_k a1,a2...ak,满足:对于任意的 i i i a i = a k − i + 1 a_i=a_{k-i+1} ai=aki+1,这就是 S S S的一个“回文划分”,它被分成了 k k k块。
请你求 S S S中被分成的块数最多的一个回文划分,输出这个最多的块数。

比如样例中的“bonobo”这个串,最大的划分就是“bo/no/bo”,3块。

思路框架

从两边往中间,每次找最短的串,使得它在前面和后面同时出现(哈希判断)。

到最后,如果 n n n为奇数,或者中间一块不能再分了,就把答案 + 1 +1 +1(中间一块单独划分出来)。

代码


#include <bits/stdc++.h>using namespace std;
namespace Flandre_Scarlet
{
    #define N 1666666
    #define hint unsigned long long //自然溢出的哈希
    #define F(i,l,r) for(int i=l;i<=r;++i)
    #define D(i,r,l) for(int i=r;i>=l;--i)
    #define Fs(i,l,r,c) for(int i=l;i<=r;c)
    #define Ds(i,r,l,c) for(int i=r;i>=l;c)
    #define MEM(x,a) memset(x,a,sizeof(x))
    #define FK(x) MEM(x,0)
    #define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
    #define p_b push_back
    #define sz(a) ((int)a.size())
    #define iter(a,p) (a.begin()+p)
    void R1(int &x)
    {
        x=0;char c=getchar();int f=1;
        while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=(f==1)?x:-x;
    }
    void Rd(int cnt,...)
    {
        va_list args;
        va_start(args,cnt);
        F(i,1,cnt) 
        {
            int* x=va_arg(args,int*);R1(*x);
        }
        va_end(args);
    }

    char a[N]; int n;
    void Input()
    {
        scanf("%s",a+1); n=strlen(a+1);
    }

    void Soviet()
    {
        hint base=79;
        hint s1=0,s2=0,b=1;
        int ans=0;
        F(i,1,n/2)
        {
            s1=s1*base+a[i]; //在s1后面加入a[i]
            s2=s2+a[n-i+1]*b; //在s2的前面加入a[i]
            b*=base;
            if (s1==s2) {ans+=2;s1=s2=0,b=1;} //找到第一个满足条件就记录答案
        }
        if (n%2 or s1) ++ans;
        printf("%d\n",ans);
    }

    #define Flan void
    Flan IsMyWife()
    {
        int t;R1(t);
        while(t--)
        {
            Input();
            Soviet();
        }
    }
}
int main(){
    Flandre_Scarlet::IsMyWife();
    getchar();getchar();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值