现在的位置: 首页 > 综合 > 正文

wikioi 2013 LNOI good串

2017年04月24日 ⁄ 综合 ⁄ 共 3589字 ⁄ 字号 评论关闭

1.对于给定的一个长度是N的0,1字符串S = s1s2...sn

2.S的子串S(l,r) = [sl,sl+1,sl+2,...,sr]。

3.若S(l,r)中'0'的个数是'1'个数的2倍,称S(l,r)这个为good串,否则为bad串。

 

选择一对整数a, b (1 <= a <= b <= N)。

Num1:开始位置l和结束位置r都在闭区间[a,b]上的子串中good串的个数;

Num2:开始位置l和结束位置r都不在闭区间[a,b]上的子串中good串的个数,但可以包含[a,b]子串,即l,r有如下三种情况l<a且r<a,l>b且r>b,l<a且r>b;

求有多少对a, b使得Num1与Num2相等?

第一行输入一个整数n。

第二行输入一个由’0’和’1’组成的长度为n的字符串。

输出一个整数,即使Num1和Num2相等的a,b数对。

3

010

4

[a,b]=[1,1]时:

       开始位置l和结束位置r都在闭区间[a,b]上的子串如下:

       "0"(good子串的个数是0个)。

       开始位置l和结束位置r都不在闭区间[a,b]上的子串如下:

       "1","0","10"(good子串的个数是0个)。

所以[1,1]满足条件。

 

[a,b]=[1,2]时:

       开始位置l和结束位置r都在闭区间[a,b]上的子串如下:

       "0","1","01"(good子串的个数是0个)。

       开始位置l和结束位置r都不在闭区间[a,b]上的子串如下:

       "0"(good子串的个数是0个)。

所以[1,2]满足条件。

 

[a,b]=[1,3]时:

       开始位置l和结束位置r都在闭区间[a,b]上的子串如下:

       "0","1","0","01","10","010"(good子串的个数是1个:"010")。

       不存在开始位置l和结束位置r都不在闭区间[a,b]上的子串(good子串的个数是0个)。

所以[1,3]不满足条件。

 

[a,b]=[2,2]时:

       开始位置l和结束位置r都在闭区间[a,b]上的子串如下:

       "1"(good子串的个数是0个)。

       开始位置l和结束位置r都不在闭区间[a,b]上的子串如下:

       "0","0","010"(good子串的个数是1个:"010")。

所以[2,2]不满足条件。

 

[a,b]=[2,3]时:

       开始位置l和结束位置r都在闭区间[a,b]上的子串如下:

       "1","0","10"(good子串的个数是0个)。

       开始位置l和结束位置r都不在闭区间[a,b]上的子串如下:

       "0"(good子串的个数是0个)。

所以[2,3]满足条件。

 

[a,b]=[3,3]时:

       开始位置l和结束位置r都在闭区间[a,b]上的子串如下:

       "0"(good子串的个数是0个)。

       开始位置l和结束位置r都不在闭区间[a,b]上的子串如下:

       "0","1","01"(good子串的个数是0个)。

所以[3,3]满足条件。

 

所以有4对a,b满足题意。

 

10%的数据中1<=N<=60;

30%的数据中1<=N<=1000;

40%的数据中1<=N<=5000;

100%的数据中1<=N<=100000;

为什么这道题没有人做?

不要任何高级数据结构,,,居然压轴题

不过蒟蒻还是想了很久,方法很巧妙,看看代码就知道了

几次90分,有一组运行错误,数组超内存了

事实证明O(n^2)可以过(没想通),不会写离散化,用了现学的map,O(nlogn)

//#define _TEST _TEST
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
//////////////////////////////////////////////////
const int maxn=100000+10;
int n;
int a[maxn];
int sum_lr[maxn];//sum(1,i)
int sum_rl[maxn];//sum(i,n)
int num[maxn*3];//num(i+maxn)
int good_l[maxn];
int good_r[maxn];

/*
令good[l][r]:[l,r]的good串个数 
找出所有(l,r):good[1][n]-good[1][r]-good[l][n]+good[l][r]+good[1][l-1]+good[r+1][n]=good[l][r]
good[1][n]+good[1][l-1]+good[r+1][n]=good[1][r]+good[l][n]
good_l[n]+good_l[l-1]+good_r[r+1]=good_l[r]+good_r[l]

枚举l,算 good_l[n]+good_l[l-1]-good_r[l]=good_l[r]-good_r[r+1] 的个数(预处理) 

good[1][i]=1<=l<r<=i:sum_lr[l-1]=sum_lr[r]的个数 
*/

map<int,int> num_good_r; 
int k=0;
//////////////////////////////////////////////////

//////////////////////////////////////////////////
void input()
{
     scanf("%d\n",&n);
     for(int i=1;i<=n;i++) a[i]=getchar()=='0'?-1:2;
}
void solve()
{
     //init
     int ans=0;
     //calculate
     for(int i=1;i<=n;i++) sum_lr[i]=sum_lr[i-1]+a[i];
     for(int i=n;i>=1;i--) sum_rl[i]=sum_rl[i+1]+a[i];
     
     memset(num,0,sizeof(num));
     num[maxn]=1;
     for(int i=1;i<=n;i++)
     {
         good_l[i]=good_l[i-1]+num[sum_lr[i]+maxn];
         num[sum_lr[i]+maxn]++;
     }

     memset(num,0,sizeof(num));
     num[maxn]=1;
     for(int i=n;i>=1;i--)
     {
         good_r[i]=good_r[i+1]+num[sum_rl[i]+maxn];
         num[sum_rl[i]+maxn]++;
     }
     
     //暴力O(n^2)
     /*for(int l=1;l<=n;l++)
     for(int r=l;r<=n;r++) if(good_l[n]+good_l[l-1]+good_r[r+1]==good_l[r]+good_r[l])
     ans++;*/
     
     
     for(int i=1;i<=n;i++)
     {
         num_good_r[good_l[i]-good_r[i+1]]++;
     }
     
     for(int i=1;i<=n;i++) ans+=num_good_r[good_l[n]+good_l[i-1]-good_r[i]];
     /*for(int i=1;i<=n;i++) printf("%d ",a[i]);puts("");
     for(int i=1;i<=n;i++) printf("%d ",sum_lr[i]);puts("");
     for(int i=1;i<=n;i++) printf("%d ",sum_rl[i]);puts("");
     for(int i=1;i<=n;i++) printf("good_l[%d]=%d good_r[%d]=%d\n",i,good_l[i],i,good_r[i]);*/
     //output
     printf("%d\n",ans);
}
//////////////////////////////////////////////////
int main()
{
     #ifndef _TEST
     freopen("2013.in","r",stdin); freopen("2013.out","w",stdout);
     #endif
     input();
     solve();
     #ifdef _TEST
     for(;;);
     #endif
     return 0;
}

抱歉!评论已关闭.