zoukankan      html  css  js  c++  java
  • [POI2010] Antisymmetry

    zz:http://hzwer.com/6527.html

    对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串。比如00001111和010101就是反对称的,1001就不是。
    现在给出一个长度为N的01字符串,求它有多少个子串是反对称的。

    Input

    第一行一个正整数N (N <= 500,000)。第二行一个长度为N的01字符串。

    Output

    一个正整数,表示反对称子串的个数。

    Sample Input

    8
    11001011

    Sample Output

    7
    hint
    7个反对称子串分别是:01(出现两次), 10(出现两次), 0101, 1100和001011

    题解

    枚举中点,然后二分+哈希求能匹配的最长距离。。。

    例解,对于样例

    在第2个位置,扩展长度为2
    在第4个位置,扩展长度为1
    在第5个位置,扩展长度为3
    在第6个位置,扩展长度为1

    /*
    input 
    8
    11110000
    output 
    4
    当以第4个位置为中心进行扩展时,可以扩展的最大长度为4,于是就有4种子串满足条件 
    */
    #include<set>
    #include<map>
    #include<ctime>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define inf 1000000000
    #define pa pair<int,int>
    #define ll long long 
    #define mod 1000000007
    using namespace std;
    ll read()
    {
    	ll x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    ll tot;
    int n;
    ll s1[500005],s2[500005],I[500005];
    char ch[500005];
    int query(int f,int l,int r)
    {
    	ll t;
    	if(!f)t=s1[r]-s1[l-1]*I[r-l+1];
    	else t=s2[l]-s2[r+1]*I[r-l+1];
    	t=(t%mod+mod)%mod;
    	return t;
    }
    void solve(int x)
    {
    	int l=1,r=min(x,n-x),ans=0;
    	//l,r为可扩展的长度左边界,右边界 
    	 
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(query(0,x-mid+1,x)==query(1,x+1,x+mid))
    			ans=mid,l=mid+1;
    		else 
    		    r=mid-1;
    	}
    	tot+=ans; 
    	//向左右扩展的最大长度为ans,则以x为中间,可以有ans种长度进行扩展 
    }
    int main()
    {
    	n=read();
    	scanf("%s",ch+1);
    	I[0]=1;
    	for(int i=1;i<=n;i++)I[i]=I[i-1]*149%mod;
    	for(int i=1;i<=n;i++) //left
    	{
    		s1[i]=s1[i-1]*149+ch[i]-'0';
    		s1[i]%=mod;
    	}
    	for(int i=n;i>=1;i--) //right
    	{
    		s2[i]=s2[i+1]*149+((ch[i]-'0')^1);
    		s2[i]%=mod;
    	}
    	for(int i=1;i<=n;i++) //枚举中间点,从中间点向左右扩张 
    	{
    	
    		solve(i);
    		cout<<i<<"    "<<tot<<endl;
    }
    	printf("%lld",tot);
    	return 0;
    }
    

      

  • 相关阅读:
    swoole 安装方法 使用即时聊天
    git的介绍以及简单应用
    curl的应用
    linux下监听和同步代码配置
    mac skim 修改背景色
    php 编译安装的一个 configure 配置
    mac mysql error You must reset your password using ALTER USER statement before executing this statement.
    yii2 控制器里 action 大小写组合造成的路由问题
    warning : json_decode(): option JSON_BIGINT_AS_STRING not implemented in xxx
    redis 自启动脚本
  • 原文地址:https://www.cnblogs.com/cutemush/p/12394709.html
Copyright © 2011-2022 走看看