Good Bye 2019 F. Awesome Substrings(字符串 分块 Hash表)

http://codeforces.com/problemset/problem/1270/F

题意:

给出一个01串,一个子串要求:字符串长度为内部1的数量的倍数,至少一个1。问有多少个。

解析:

子串 [ l + 1 , r ] [l+1,r] ,要求 r l = K ( F r F l ) r-l=K(F_r-F_l) ,其中 F i F_i 为前缀的1的个数。

  • K n K\leq\sqrt n
    • 式子转化为 r K F r = l K F l r-KF_r=l-KF_l ,枚举 K [ 1 , n ] K\in[1,\sqrt n] ,将 i K F i i-KF_i 统计即可。( C n 2 C_n^2 ,边遍历边做就是加上之前的个数,再计数器++)
  • K > n K>\sqrt n
    • 此时显然有: ( F r F l ) < n (F_r-F_l)<\sqrt n ,也就是说需要统计的串中1的个数小于 n \sqrt n 。所以可以枚举子串的左端点,向右拓展至多 n \sqrt n 个1。
    • 此时有一个固定1数量的区间,假设长度为 [ L , R ] [L,R] ,要求 K > n K>\sqrt n ,所以 L = m a x ( L , ( n + 1 ) c n t 1 ) L=max(L,(\sqrt n+1)cnt_1) 。最后统计区间内 c n t 1 cnt_1 的倍数即可。

因为已经有 O ( n n ) O(n\sqrt n) 的时间复杂度,所以 K n K\leq\sqrt n 时统计出现次数不能用std里面的东西,就自己写了一个哈希链表。

代码:

/*
 *  Author : Jk_Chen
 *    Date : 2020-02-19-16.39.12
 */
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
#define debug(x) cerr<<#x<<" = "<<x<<'\n'
const LL mod=1e9+7;
const int maxn=2e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
    while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/

char x[maxn];
int pre[maxn];
int nex[maxn];

unordered_map<int,int>cnt;
namespace Hash{
    const int Mod=1e6+9;
    int head[Mod],nex[Mod],now;
    struct node{
        int val;
        int cnt;
    } val[Mod];
    void init(){
        now=0;
        mmm(head,0);
    }
    node* Find(int v){
        int key=(v%Mod+Mod)%Mod;
        for(int i=head[key];i;i=nex[i]){
            if(val[i].val==v)
                return &val[i];
        }
        return nullptr;
    }
    void Insert(int v){
        node* P=Find(v);
        if(P==nullptr){
            int key=(v%Mod+Mod)%Mod;
            nex[++now]=head[key];head[key]=now;val[now].val=v,val[now].cnt=1;
        }
        else{
            P->cnt++;
        }
    }
}
/*_________________________________________________________Hash*/

int main(){
    scanf("%s",x+1);
    int n=strlen(x+1);
    rep(i,1,n){
        pre[i]=x[i]-'0'+pre[i-1];
    }
    int UP=sqrt(n);
    LL ans=0;
    rep(K,1,UP){
        Hash::Insert(0);
        rep(i,1,n){
            auto P=Hash::Find(i-K*pre[i]);
            if(P!=nullptr){
                ans+=P->cnt;
                P->cnt++;
            }
            else
                Hash::Insert(i-K*pre[i]);
        }
        Hash::init();
    }
    int nx=-1;
    per(i,n,1){
        nex[i]=nx;
        if(x[i]=='1')nx=i;
    }
    rep(i,1,n){
        int r=i;
        if(x[i]=='0')r=nex[i];
        if(r==-1)break;
        int cnt=1;
        rep(_,1,UP){
            int L=r-i+1,R=nex[r]-1-i+1;
            if(nex[r]==-1)R=n-i+1;
            L=max(L,(UP+1)*cnt);
            if(L<=R){
                ans+=R/cnt-(L-1)/cnt;
            }

            r=nex[r];
            cnt++;
            if(r==-1)break;
        }
    }
    printf("%lld\n",ans);

    return 0;
}

/*_________________________________________________________end*/

发布了773 篇原创文章 · 获赞 345 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/104406746