bzoj-2084 Antisymmetry

 题意:

定义一个串反对称 为 将其01取反之后,翻转之后与原串相同;

给出一个长度为n的01串,求这个串中有多少子串为反对称串;

n<=500000;

题解:

马拉车算法。。

然而作为一个蒟蒻我还是滚回去复习了一遍manacher啥的;

首先这题有个性质:反对称串一定是偶数长的串;

所以我们其实跑的只是偶数串的算法,也就是可以不加#分隔的姿势;

(你不觉得不加#####十分优雅吗?)

然后改一下判断参数就是反对称串了;

对于算法的实现细节就看代码吧,这题也真是没啥说的;

时间复杂度O(n);

代码:

#include<cctype>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 531072
using namespace std;
bool str[N];
int f[N];
int main()
{
    int n,m,i,j,k,id,ma;
    long long ans;
    char ch;
    scanf("%d",&n);
    while(!isdigit(ch=getchar()));
    str[1]=ch-'0';
    for(i=2;i<=n;i++)
        str[i]=getchar()-'0';
    for(i=1,ma=0,id=0,ans=0;i<=n;i++)
    {
        if(f[i]<=ma)
            f[i]=max(f[i],min(f[id+id-i],ma-i));
        while(str[i+f[i]+1]==!str[i-f[i]]&&i+f[i]+1<=n&&i-f[i]>0)
            f[i]++;
        if(i+f[i]>ma)
            ma=i+f[i],id=i;
        ans+=f[i];
    }
    printf("%lld\n",ans);
    return 0;
}
时间: 2024-08-11 05:44:08

bzoj-2084 Antisymmetry的相关文章

bzoj 2084: [Poi2010]Antisymmetry -- manacher

2084: [Poi2010]Antisymmetry Time Limit: 10 Sec  Memory Limit: 259 MB Description 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串.比如00001111和010101就是反对称的,1001就不是.现在给出一个长度为N的01字符串,求它有多少个子串是反对称的. Input 第一行一个正整数N (N <= 500,000).第二行一个长度为N的01字符串. Output

BZOJ 2084: [Poi2010]Antisymmetry

2084: [Poi2010]Antisymmetry Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 596  Solved: 379[Submit][Status][Discuss] Description 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串.比如00001111和010101就是反对称的,1001就不是.现在给出一个长度为N的01字符串,求它有多少个子串是反对称的. Input

BZOJ 2084 [Poi2010]Antisymmetry(manacher)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2084 [题目大意] 对于一个01字符串,如果将这个字符串0和1取反后, 再将整个串反过来和原串一样,就称作“反对称”字符串. 比如00001111和010101就是反对称的,1001就不是. 现在给出一个长度为N的01字符串,求它有多少个子串是反对称的. [题解] 修改manacher的判定条件,对该串进行计算即可. [代码] #include <cstdio> #include

BZOJ 2084 Poi2010 Antisymmetry Manacher算法

题目大意:给定一个长度为n的01串,问有多少个子串满足翻转并取反后和原来一样 定义0=1,0≠0,1≠1,跑Manacher即可 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 500500 using namespace std; int n; char s[M]; long long Manacher(char str[],in

bzoj 2084

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2084 这道题很容易想到就是一个变种的最长回文字串, 不过回文的规则变成了s[i + p[i]] + s[i - p[i]] == 1 可以用hash 来nlogn, 不过最优是用manacher, 然后有一个非常迷的查空位的方法(' '       ) 可以看代码 #include <iostream> #include <cstring> #include <algo

BZOJ 2084 二分+hash OR Manacher

思路: 二分+哈希 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N=500050; const ll mod=1000000007; int n; ll hs1[N],hs2[N],base[N],Ans; char s1[N],s2[N]; int main(){

【BZOJ】【2084】【POI2010】Antisymmetry

Manacher算法 啊……Manacher修改一下就好啦~蛮水的…… Manacher原本是找首尾相同的子串,即回文串,我们这里是要找对应位置不同的“反回文串”(反对称?233) 长度为奇数的肯定不满足>_>(中间那个字符无论如何不反对称) 那么我们就找'#'为中心的即可…… 将判断条件a[i-p[i]-1]==a[i+p[i]+1]改成[不等……或是两个都是'#'] 将所有的p[i]加起来,即所有“反回文串”的长度加起来除以二就是答案啦~ 看代码吧>_< 1 /********

[Strings]一些字符串题目

Trie BZOJ 3689 异或之 大意: 给定n个数,求这n个数两两异或的值中的前k小 解: 将加法换成异或就变成了一个用堆合并多个有序表的经典问题,对于加法我们按大小排序就能得到有序表,而由于这里是异或,我们需要高效地维护有序表,即对于一个数ai快速求出与它异或第k小的数. 我们将所有数按二进制建成Trie,然后在Trie的结点上记录下子树中的结束结点个数,再在Trie树上走一遍就得到了答案 BZOJ 3439 Kpm的MC密码 大意: 给定n个字符串,对于每个字符串求以这个字符串为后缀的

bzoj2084【POI2010】Antisymmetry

2084: [Poi2010]Antisymmetry Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 432  Solved: 273 [Submit][Status][Discuss] Description 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作"反对称"字符串.比如00001111和010101就是反对称的,1001就不是. 现在给出一个长度为N的01字符串,求它有多少个子串是反对称

BZOJ2084: [Poi2010]Antisymmetry

2084: [Poi2010]Antisymmetry Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 187  Solved: 125[Submit][Status] Description 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串.比如00001111和010101就是反对称的,1001就不是.现在给出一个长度为N的01字符串,求它有多少个子串是反对称的. Input 第一行一个正整数