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

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

題意:

給出一個01串,一個子串要求:字符串長度爲內部1的數量的倍數,至少一個1。問有多少個。

解析:

子串[l+1,r][l+1,r],要求rl=K(FrFl)r-l=K(F_r-F_l),其中FiF_i爲前綴的1的個數。

  • KnK\leq\sqrt n
    • 式子轉化爲rKFr=lKFlr-KF_r=l-KF_l,枚舉K[1,n]K\in[1,\sqrt n],將iKFii-KF_i統計即可。(Cn2C_n^2,邊遍歷邊做就是加上之前的個數,再計數器++)
  • K>nK>\sqrt n
    • 此時顯然有:(FrFl)<n(F_r-F_l)<\sqrt n,也就是說需要統計的串中1的個數小於n\sqrt n。所以可以枚舉子串的左端點,向右拓展至多n\sqrt n個1。
    • 此時有一個固定1數量的區間,假設長度爲[L,R][L,R],要求K>nK>\sqrt n,所以L=max(L,(n+1)cnt1)L=max(L,(\sqrt n+1)cnt_1)。最後統計區間內cnt1cnt_1的倍數即可。

因爲已經有O(nn)O(n\sqrt n)的時間複雜度,所以KnK\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*/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章