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 <cstring>
using namespace std;
const int N=1000010;
int n,m,i,r,p,f[N<<1];
long long ans;
char a[N],s[N<<1];
int min(int a,int b){return a<b?a:b;}
bool check(char x,char y){
    if(x==‘#‘&&y==‘#‘)return 1;
    if((x-‘0‘)+(y-‘0‘)==1)return 1;
    return 0;
}
void manacher(char *a){
    for(i=1;i<=n;i++)s[i<<1]=a[i],s[i<<1|1]=‘#‘;
    s[0]=‘$‘,s[1]=‘#‘,s[m=(n+1)<<1]=‘&‘;
    for(r=p=0,f[1]=1,i=1;i<m;ans+=f[i++]>>1){
        for(f[i]=r>i?min(r-i,f[p*2-i]):0;check(s[i-f[i]],s[i+f[i]]);f[i]++);
        if(i+f[i]>r)r=i+f[i],p=i;
        //printf("%d\n",f[i]);
    }
}
int main(){
    scanf("%d",&n);
    scanf(" %s",a+1);
    manacher(a);
    printf("%lld\n",ans);
    return 0;
}
时间: 2024-10-13 12:18:22

BZOJ 2084 [Poi2010]Antisymmetry(manacher)的相关文章

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算法

题目大意:给定一个长度为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

hdu3294Girls&#39; research(manacher)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3294 题目不难,感觉输出比较麻烦. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=2000010; 6 char s[maxn<<1]; 7 int r[maxn<<1]; 8 char ans[

BZOJ 1076 奖励关(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1076 题意:n种宝物,每个宝物有两个属性: (1)价值:(2)该宝物的集合S,只有得到了集合S中的宝物时才能得到该宝物.每次从一个黑箱子中随机拿出一个宝物k,若k的集合S中的宝物都已经得 到,则k可要(也可不要),否则k不能要.每次拿到任意宝物概率相等.求随机拿K次的最大期望得分. 思路:从后向前,设f[i][j]表示到第i次拿完宝物,状态为j的最大价值.枚举i+1次拿的宝物k,若k的

BZOJ 1560 火星藏宝图(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1560 题意: 思路:f[i]表示到达i的最大收益.这样是 O(n^2)的.我们考虑,由于转移的条件,a^2+b^2<(a+b)^2,因此对于三个点A.B.C.若A能到B,B能到C,那么A也能到C, 但是不如经过B更好.因此,我们记录到达第j列最靠下的i即可.那么转移(x,y)时,用记录的前y列即可. struct node { int x,y,w; }; node a[N]; int

BZOJ 2298 problem a(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2298 题意:一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低.”问最少有几个人没有说真话(可能有相同的分数) 思路:对于第i个人来说,区间[ai+1,n-bi]的人的分数相同.那么我们用sum[L][R]表示区间[L,R]中总人数.用f[i]表示前i个人中说真话的最大人数,那么f[j]=max(f[i-1]+sum[i][j]). map<pair<in

BZOJ 1049 数字序列(LIS)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1049 题意:给出一个数列A,要求:(1)修改最少的数字使得数列严格递增:(2)在(1)的基础上使得修改的绝对值之和最小. 思路:对于第一问看起来像是求最长上升子 列,其实不是.我们想,若对于i<j,j能由i转移过来,那么需满足A[j]-A[i]>=j-i才行,这样我们发现只要A[j]-j& gt;=A[i]-i即可.因此令A[i]=A[i]-i,这样求LIS即可.对于第二问,

HDU 4513 吉哥系列故事——完美队形II(Manacher)

Problem Description 吉哥又想出了一个新的完美队形游戏! 假设有n个人按顺序站在他的面前,他们的身高分别是h[1], h[2] ... h[n],吉哥希望从中挑出一些人,让这些人形成一个新的队形,新的队形若满足以下三点要求,则就是新的完美队形: 1.挑出的人保持原队形的相对顺序不变,且必须都是在原队形中连续的: 2.左右对称,假设有m个人形成新的队形,则第1个人和第m个人身高相同,第2个人和第m-1个人身高相同,依此类推,当然如果m是奇数,中间那个人可以任意: 3.从左到中间那