zoukankan      html  css  js  c++  java
  • ihhh题解

    10分做法:

    由于空间卡得紧,所以给了10分暴力分0.0
    所以大家很容易就知道暴力就是线段树套ac自动机辣
    时间:$O((sum |qSi| + sum |nSi|)*log Q)$
    空间:$O((sum |nSi|)*log n)$

    40-50分做法:

    发现我们可以用莫队做,可是有删除操作不好搞。
    发现其实删除操作就是在trie上把一个串的trie节点的size统统删去1,然后用跑的时候这个不更新size=0的终止节点就行辣,由于fail的性质,可以证明这样做是正确的。于是维护size我们用lct。
    虽然理论复杂度和满分做法一样,可是区间修改的splay十分蛋疼,你懂的。
    我比较良心因此数据给了一些分给此做法~因此期望分就是40~50分辣。
    时间:$O(N^{1.5}log(max{|nSi|})+Qlog(max{|qSi|}))$ 
    空间:$O(sum |nSi| + sum |qSi|)$

    满分做法:

    其实发现我们可以在终止节点打个标记= =所以lct从维护trie变成维护fail树,然后就能通过全部数据辣...
    时间:$O(N^{1.5}log(max{|nSi|})+Qlog(max{|qSi|}))$
    空间:$O(sum |nSi| + sum |qSi|)$
    维护树还能用树链剖分+线段树,这种做法虽然在修改上多了一个log,但是由于常熟十分小,期望分数还是100分的,只要你没写残...
    时间:$O(N^{1.5}log(max{|nSi|})+Qlog^2(max{|qSi|}))$
    空间:$O(sum |nSi| log(sum |nSi|) + sum |qSi|)$
    妈呀你们做题才发现这题能被分块水掉............
    完了完了我的人生啊.............

    完了完了saffah大爷说了一种秒标程的做法:

    同样是建线段树,然后我们查询一个区间的时候先标记,总共会标记$O(QlogN)$个节点,然后我们对每个标记的节点再建ac自动机,查询完一个就rebuild自动机....这样空间就不会爆了......orz
    这样每个串最多被build到$O(log(N))$个自动机内,因此查询复杂度为$O(log(N) sum |nSi|)$

    乱搞?

    1、暴力修改终止节点:然而fail树高度最坏$O(max{S})$。(咦好像数据并没有出全a的数据,没水过的估计被卡常了?) 、、
    2、分块大发:似乎这是正解...然而还是被卡常了.....

    PS:

    复杂度和最长串长度有关?然而好像我造的随机数据并没有太长QAQ

    满分第一种做法(ac自动机+莫队+lct):

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1e5+10, nQ=1e5+10, nSz=26, S=5*1e5+10;
    struct node *null, *root;
    struct node {
    	node *c[2], *f, *ch[nSz], *fail;
    	int n, mx, tag;
    	void init() { c[0]=c[1]=f=null; fail=root; for(int i=0; i<nSz; ++i) ch[i]=root; mx=n=tag=0; }
    	bool d() { return f->c[1]==this; }
    	bool isson() { return f->c[0]==this || f->c[1]==this; }
    	void setc(node *x, bool d) { c[d]=x; x->f=this; }
    	void up() { mx=max(c[0]->mx, c[1]->mx); if(tag) mx=max(mx, n); }
    }Po[S], *iT=Po, *pos[N], *s[S];
    node *newnode() { iT->init(); return iT++; }
    void rot(node *x) {
    	node *f=x->f; bool d=x->d();
    	if(f->isson()) f->f->setc(x, f->d());
    	else x->f=f->f;
    	f->setc(x->c[!d], d);
    	x->setc(f, !d);
    	f->up();
    }
    void splay(node *x) {
    	while(x->isson())
    		if(!x->f->isson()) rot(x);
    		else x->d()==x->f->d()?(rot(x->f), rot(x)):(rot(x), rot(x));
    	x->up();
    }
    node *access(node *x) { node *y=null; for(; x!=null; y=x, x=x->f) splay(x), x->c[1]=y; return y; }
    void add(char *s, int id) {
    	int n=strlen(s); node *now=root;
    	for(int i=0; i<n; ++i) {
    		int x=s[i]-'a';
    		if(now->ch[x]==root) now->ch[x]=newnode();
    		now=now->ch[x];
    	}
    	now->n=n; pos[id]=now;
    }
    void bfs() {
    	int fr=0, ta=0;
    	s[ta++]=root; node *x;
    	while(fr!=ta) {
    		x=s[fr++];
    		for(int i=0; i<nSz; ++i)
    			if(x->ch[i]!=root) {
    				s[ta++]=x->ch[i];
    				if(x==root) continue;
    				x->ch[i]->fail=x->fail->ch[i];
    				x->ch[i]->f=x->ch[i]->fail;
    			}
    			else x->ch[i]=x->fail->ch[i];
    	}
    }
    int getans(char *s, int n) {
    	int ans=0; node *now=root;
    	for(int i=0; i<n; ++i) {
    		int x=s[i]-'a';
    		now=now->ch[x];
    		access(now); splay(now); ans=max(ans, now->mx);
    	}
    	return ans;
    }
    void update(int x, int f) { splay(pos[x]); pos[x]->tag+=f; pos[x]->up(); }
    int blc[nQ], n, Q, nowid=0;
    char a[S];
    struct qq { int l, r, id, n, pos; }q[nQ];
    bool cmp1(const qq &a, const qq &b) { return blc[a.l]==blc[b.l]?a.r<b.r:a.l<b.l; }
    bool cmp2(const qq &a, const qq &b) { return a.id<b.id; }
    void init() {
    	null=iT++; root=iT++; null->init(); root->init();
    	for(int i=0, sq=sqrt(n+0.5); i<n; ++i) blc[i]=i/sq;
    }
    int main() {
    	scanf("%d%d", &n, &Q);
    	init();
    	for(int i=0; i<n; ++i) { scanf("%s", a); add(a, i); }
    	for(int i=0; i<Q; ++i) { int l, r; scanf("%d%d%s", &l, &r, a+nowid); --l; --r; q[i]=(qq){l, r, i, (int)strlen(a+nowid), nowid}; nowid+=q[i].n; }
    	bfs();
    	sort(q, q+Q, cmp1);
    	int l=0, r=-1;
    	for(int i=0; i<Q; ++i) {
    		int nl=q[i].l, nr=q[i].r;
    		while(nl<l) update(--l, 1);
    		while(nl>l) update(l++, -1);
    		while(nr<r) update(r--, -1);
    		while(nr>r) update(++r, 1);
    		blc[q[i].id]=getans(a+q[i].pos, q[i].n);
    	}
    	for(int i=0; i<Q; ++i) printf("%d
    ", blc[i]);
    	return 0;
    }
    

      

    满分第二种做法(ac自动机+莫队+树剖+线段树):

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    struct edge {
        int t;
        edge *next;
    };
    struct qry {
        char* str;
        int len, l, r, bl, i;
    };
    struct seg {
        int l, r, s, c, v;
        seg *ls, *rs;
    };
    inline bool cmpQry(const qry& a, const qry& b) {
        if (a. bl == b. bl)
            return a. r > b. r;
        else
            return a. bl < b. bl;
    }
    
    const int maxn = 100009;
    const int maxlen = 500009;
    
    int n, m, bsz, ans[maxn];
    int tr[maxlen][27], fl[maxlen], ep[maxn], tn, dep[maxlen];
    int d[maxlen], sz[maxlen], tc, fc[maxlen], ch[maxlen], cl[maxlen];
    char g[maxlen], cbuf_arr[maxlen], *cbuf(cbuf_arr);
    qry q[maxn];
    edge ebuf_arr[maxlen << 1], *ebuf(ebuf_arr), *head[maxlen];
    seg sbuf_arr[maxn << 2], *sbuf(sbuf_arr), *rt[maxlen];
    
    int trieIns(char* a) {
        int p(1);
        for (; *a; ++ a) {
            int d(*a - 97);
            if (!tr[p][d])
                dep[tr[p][d] = ++ tn] = dep[p] + 1;
            p = tr[p][d];
        }
        return p;
    }
    inline void addEdge(int u, int v) {
        ebuf-> t = v;
        ebuf-> next = head[u];
        head[u] = ebuf ++;
    }
    
    #define cpos(_p_) (d[_p_]-d[ch[fc[_p_]]])
    #define midp(_p_) ((_p_->l+_p_->r)>>1)
    inline seg* sgtBuild(int l, int r) {
        seg* p(sbuf ++);
        p-> l = l, p-> r = r;
        p-> s = 0, p-> c = 0;
        if (l + 1 < r) {
            p-> ls = sgtBuild(l, midp(p));
            p-> rs = sgtBuild(midp(p), r);
        }
        return p;
    }
    inline void sgtChg(seg* p, int po, int v) {
        if (p-> l + 1 == p-> r) {
            p-> c += v;
            if (p-> c)
                p-> s = p-> v;
            else
                p-> s = 0;
        }
        else {
            if (po < midp(p))
                sgtChg(p-> ls, po, v);
            else
                sgtChg(p-> rs, po, v);
            p-> s = max(p-> ls-> s, p-> rs-> s);
        }
    }
    inline void sgtSet(seg* p, int po, int vo) {
        if (p-> l + 1 == p-> r)
            p-> v = vo;
        else if (po < midp(p))
            sgtSet(p-> ls, po, vo);
        else
            sgtSet(p-> rs, po, vo);
    }
    inline int sgtQry(seg* p, int po) {
        if (p-> r == po)
            return p-> s;
        else if (po <= midp(p))
            return sgtQry(p-> ls, po);
        else
            return max(p-> ls-> s, sgtQry(p-> rs, po));
    }
    
    void acaBuild() {
        static int q[maxlen];
        int hd(0), tl(1);
        fl[q[0] = 1] = 0;
        d[1] = 1;
        while (hd < tl) {
            int u(q[hd ++]), v;
            for (int i = 0; i < 26; ++ i)
                if ((v = tr[u][i])) {
                    int w;
                    for (w = fl[u]; w && !tr[w][i]; w = fl[w]);
                    if (!w)
                        fl[v] = 1;
                    else
                        fl[v] = tr[w][i];
                    d[v] = d[fl[v]] + 1;
                    addEdge(fl[v], v);
                    q[tl ++] = v;
                }
        }
        tc = 0;
        for (int i = tl - 1; i >= 0; -- i) {
            int p(q[i]), z(-1);
            sz[p] = 1;
            for (edge* e = head[p]; e; e = e-> next) {
                sz[p] += sz[e-> t];
                if (z == -1 || sz[e-> t] > sz[z])
                    z = e-> t;
            }
            if (z == -1)
                cl[fc[p] = ++ tc] = 1;
            else
                ++ cl[fc[p] = fc[z]];
            ch[fc[p]] = p;
        }
        for (int i = 1; i <= tc; ++ i)
            rt[i] = sgtBuild(0, cl[i]);
        for (int i = 1; i <= tn; ++ i)
            sgtSet(rt[fc[i]], cpos(i), dep[i]);
    }
    
    int getTrans(int p, int w) {
        for (; p && !tr[p][w]; p = fl[p]);
        if (p)
            return tr[p][w];
        else
            return 1;
    }
    void cptMo() {
        sort(q, q + m, cmpQry);
        int l(1), r(1);
        sgtChg(rt[fc[ep[1]]], cpos(ep[1]), 1);
        for (int i = 0; i < m; ++ i) {
            while (r < q[i]. r) {
                ++ r;
                sgtChg(rt[fc[ep[r]]], cpos(ep[r]), 1);
            }
            while (l > q[i]. l) {
                -- l;
                sgtChg(rt[fc[ep[l]]], cpos(ep[l]), 1);
            }
            while (r > q[i]. r) {
                sgtChg(rt[fc[ep[r]]], cpos(ep[r]), -1);
                -- r;
            }
            while (l < q[i]. l) {
                sgtChg(rt[fc[ep[l]]], cpos(ep[l]), -1);
                ++ l;
            }
            int g(0);
            for (int p = 1, j = 0; j < q[i]. len; ++ j) {
                p = getTrans(p, q[i]. str[j] - 97);
                for (int u = p; u; u = fl[ch[fc[u]]])
                    g = max(g, sgtQry(rt[fc[u]], cpos(u) + 1));
            }
            ans[q[i]. i] = g;
        }
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        bsz = (int)pow(n, 0.5) + 1;
        dep[tn = 1] = 0;
        for (int i = 1; i <= n; ++ i) {
            scanf("%s", g);
            ep[i] = trieIns(g);
        }
        acaBuild();
        for (int i = 0; i < m; ++ i) {
            scanf("%d%d%s", &q[i]. l, &q[i]. r, cbuf);
            q[i]. len = strlen(q[i]. str = cbuf);
            cbuf += q[i]. len;
            q[i]. bl = q[i]. l / bsz;
            q[i]. i = i;
        }
        cptMo();
        for (int i = 0; i < m; ++ i)
            printf("%d
    ", ans[i]);
    }
    

      

    满分第三种做法(还没写...):

  • 相关阅读:
    时间序列算法(平稳时间序列模型,AR(p),MA(q),ARMA(p,q)模型和非平稳时间序列模型,ARIMA(p,d,q)模型)的模型以及需要的概念基础学习笔记梳理
    Python两步实现关联规则Apriori算法,参考机器学习实战,包括频繁项集的构建以及关联规则的挖掘
    基于逻辑回归的利用欠采样处理类别不平衡的信用卡欺诈检测
    利用sklearn对MNIST手写数据集开始一个简单的二分类判别器项目(在这个过程中学习关于模型性能的评价指标,如accuracy,precision,recall,混淆矩阵)
    利用Sklearn实现加州房产价格预测,学习运用机器学习的整个流程(包含很多细节注解)
    Javax虚拟机-常见的JVM工具
    Java虚拟机-虚拟机字节码执行引擎
    Java虚拟机-虚拟机类加载机制
    Java虚拟机-类文件结构
    Java虚拟机-内存分配策略
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4535539.html
Copyright © 2011-2022 走看看