zoukankan      html  css  js  c++  java
  • 【bzoj2754】 SCOI2012—喵星球上的点名

    http://www.lydsy.com/JudgeOnline/problem.php?id=2754 (题目链接)

    题意

      给出$n$个名字串,$m$个点名串,问对于每一个姓名串,它包含多少个点名串,并且每一个点名串串是多少姓名串的子串。

    Solution

      暴力踩正解,乱搞能AC。暴跳fail即可

      网上终于找到了正解:http://blog.csdn.net/clover_hxy/article/details/52502544,然而不想写了。。

      

      UPD:自己脑补了一个后缀数组的做法。首先跟网上大部分后缀数组暴力的做法一样,点名串和姓名串接起来求SA。对于一个点名串长度为$len$,包含它的姓名串与它的lcp长度一定正好等于$len$。因为排好了序的后缀数组中,lcp只会随着距离的增大而减小,所以满足条件的姓名串的后缀一定是一个区间。这里最暴力的方法就是对于每一个姓名串往两边for(虽然可以AC= =),我们用ST表维护一下任意两个后缀的lcp,然后倍增求出这个区间,复杂度$O(mlog n)$

      接下来问题就转化为了:给出了一个$n$个数的序列,一共$m$个区间,问每个区间覆盖了多少个不同的数(点名串是多少姓名串的子串),每个值被多少个区间覆盖(姓名串包含多少个点名串)。两问都没有修改所以很好做。可以$O(nsqrt{n})$的莫队艹过去,或者第一问就主席树,第二问线段树$O(nlog n)$。

      所以,你还想写吗= =,三个namespace,fuck!

    细节

      buildfail时记得入队。不忽略行末空格是smg。。

    代码

    // bzoj2754
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<cmath>
    #include<queue>
    #include<map>
    #define LL long long
    #define inf (1ll<<30)
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    
    const int maxn=100010;
    int n,m,a[maxn],vis[maxn],res[maxn],ans[maxn];
    vector<int> v[maxn][2];
    struct node {
    	map<int,int> mp;
    	vector<int> end;
    	int next,cnt;
    	int& operator [] (int x) {return mp[x];}
    }tr[maxn];
    
    namespace ACM {
    	int head[maxn],cnt,sz=1;
    	struct edge {int to,next,w;}e[maxn];
    	void link(int u,int v,int w) {
    		e[++cnt]=(edge){v,head[u],w};head[u]=cnt;
    	}
    	void insert(int *r,int len,int id) {
    		int p=1;
    		for (int i=1;i<=len;i++) {
    			if (!tr[p][r[i]]) {
    				tr[p][r[i]]=++sz;
    				link(p,sz,r[i]);
    			}
    			p=tr[p][r[i]];
    		}
    		tr[p].end.push_back(id);tr[p].cnt++;
    	}
    	void buildfail() {
    		queue<int> q;q.push(1);
    		tr[1].next=0;
    		while (!q.empty()) {
    			int x=q.front();q.pop();
    			for (int i=head[x];i;i=e[i].next) {
    				int k=tr[x].next,c=e[i].w;
    				while (!tr[k][c]) k=tr[k].next;
    				tr[tr[x][c]].next=tr[k][c];
    				q.push(tr[x][c]);
    			}
    		}
    	}
    }
    using namespace ACM;
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for (int len,i=1;i<=n;i++) {
    		scanf("%d",&len);
    		for (int x,j=1;j<=len;j++) scanf("%d",&x),v[i][0].push_back(x);
    		scanf("%d",&len);
    		for (int x,j=1;j<=len;j++) scanf("%d",&x),v[i][1].push_back(x);
    	}
    	for (int i=0;i<=10000;i++) tr[0][i]=1;
    	for (int len,i=1;i<=m;i++) {
    		scanf("%d",&len);
    		for (int j=1;j<=len;j++) scanf("%d",&a[j]);
    		insert(a,len,i);
    	}
    	buildfail();
    	for (int i=1;i<=n;i++)
    		for (int t=0;t<=1;t++) {
    			int len=v[i][t].size(),p=1;
    			for (int j=0;j<len;j++) {
    				while (!tr[p][v[i][t][j]]) p=tr[p].next;
    				p=tr[p][v[i][t][j]];
    				for (int k=p;k;k=tr[k].next)
    					if (tr[k].cnt)
    						for (int l=0;l<tr[k].cnt;l++) {
    							if (vis[tr[k].end[l]]!=i) ans[tr[k].end[l]]++,res[i]++;
    							vis[tr[k].end[l]]=i;
    						}
    			}
    		}
    	for (int i=1;i<=m;i++) printf("%d
    ",ans[i]);
    	for (int i=1;i<=n;i++) {
    		printf("%d",res[i]);
    		if (i<n) printf(" ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    JQUERY 判断选择器选择的对象 是否存在
    js的reduce方法,改变头等函数
    盒模型 bug 与触发 bfc
    CSS(四)float 定位
    CSS(三)背景 list-style display visibility opacity vertical cursor
    css 负边距
    CSS(二) 颜色 盒模型 文字相关 border
    CSS(一) 引入方式 选择器 权重
    html总结
    主流浏览器及内核
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6504394.html
Copyright © 2011-2022 走看看