文章目录
R e s u l t Result Result
暴力:
正解:
H y p e r l i n k Hyperlink Hyperlink
http://noip.ybtoj.com.cn/contest/105/problem/2
D e s c r i p t i o n Description Description
给定一个01串 s s s, T T T组询问,每次询问给定一个串 t t t,询问 s s s有多少个长度和 t t t一样的子串,使得区间的1的和相同
数据范围: ∣ s ∣ ≤ 2 × 1 0 5 , ∑ ∣ t ∣ ≤ 2 × 1 0 5 , T ≤ 2 × 1 0 5 |s|\leq 2\times 10^5,\sum |t|\leq 2\times 10^5,T\leq 2\times 10^5 ∣s∣≤2×105,∑∣t∣≤2×105,T≤2×105
S o l u t i o n Solution Solution
暴力能过。。。。当然我们要想更加优秀的做法
由于 t t t的长度和是有限的,这就引出了优秀的性质,即
- t t t的长度的种类不会超过 n \sqrt n n种
- ∣ t ∣ > n |t|> \sqrt n ∣t∣>n 的至多有 n \sqrt n n个
根据性质1,我们可以将询问离线,同种长度的一起计算,时间复杂度: O ( n n ) O(n\sqrt n) O(nn)
根据性质2,我们可以长度 ≤ n \leq \sqrt n ≤n的答案提前预处理出来,具体地,设 f i , j f_{i,j} fi,j表示长度为 i i i和为 j j j的串的个数,预处理是 O ( n n ) O(n\sqrt n) O(nn)的,然后对于 ∣ t ∣ ≤ n |t|\leq \sqrt n ∣t∣≤n的直接 O ( 1 ) O(1) O(1)输出,大于 n \sqrt n n的直接跑,因为最多跑 n \sqrt n n次,所以是可以过得,总的时间复杂度也是 O ( n n ) O(n\sqrt n) O(nn)
性质1的话是离线的,性质2的话是在线的,代码采用的是性质2
C o d e Code Code
暴力
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define LL long long
#define N 200010
using namespace std;char s[N],st[N];
int n,S[N],m,sum,res,len;
inline LL read()
{
LL d=1,f=0;char c;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
signed main()
{
freopen("similar.in","r",stdin);
freopen("similar.out","w",stdout);
scanf("%s",s);len=strlen(s);
for(register int i=0;i<len;i++) S[i+1]=S[i]+(s[i]==49);
n=read();
while(n--)
{
scanf("%s",st);m=strlen(st);sum=0;res=0;
for(register int i=0;i<m;i++) sum+=st[i]==49;
for(register int i=0;i<=len-m+1;i++) if(S[i+m]-S[i]==sum) res++;
printf("%d\n",res);
}
}
根号分治
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define LL long long
#define N 200010
using namespace std;char s[N],st[N];
int n,S[N],m,sum,res,len,f[450][450],T;
inline LL read()
{
LL d=1,f=0;char c;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
signed main()
{
freopen("similar.in","r",stdin);
freopen("similar.out","w",stdout);
scanf("%s",s);len=strlen(s);T=sqrt(len);
for(register int i=0;i<len;i++) S[i+1]=S[i]+(s[i]==49);
for(register int i=1;i<=T;i++)
for(register int j=0;j+i<=len;j++)
f[i][S[j+i]-S[j]]++;
n=read();
while(n--)
{
scanf("%s",st);m=strlen(st);sum=0;
for(register int i=0;i<m;i++) sum+=st[i]==49;
if(m>T)
{
res=0;
for(register int i=0;i<=len-m+1;i++) if(S[i+m]-S[i]==sum) res++;
printf("%d\n",res);
}
else printf("%d\n",f[m][sum]);
}
}