zoukankan      html  css  js  c++  java
  • 字符串

    考虑同构的性质

    对每个字符维护上一次出现在哪个位置,容易发现对于两个串,如果他们同构,那么这两个串的 pre 序列一定是完全一样的。

    我们使用类似 SA 求 lcp 的套路,对这个东西做后缀排序。因为每个后缀的 pre 序列不一样,所以只能使用 sort+二分 Hash 然后复杂度就成了 (O(nlog^3n))

    虽然理论复杂度是对的,但奈何这个东西的常数实在是太大大大大大了,一组极限数据,本地运行了 23s。

    #include<bits/stdc++.h>
    using namespace std;
    #define u64 unsigned long long
    
    template<typename _T>
    inline void read(_T &x)
    {
    	x=0;char s=getchar();int f=1;
    	while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
    	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
    	x*=f;
    }
    
    const u64 base = 131;
    const int np = 5e4 + 5;
    const int cp = 2 * np + np * 17;
    int n,Cnt;
    u64 p[np];
    int a[np],ver[np],sa[np];
    int bac[np];
    struct Node{
    	Node *ls,*rs;
    	u64 Val;
    }mem[cp],*pool = mem,*rot[np];
    inline Node *New(){
    	++pool;
    	pool->ls = pool->rs=0;
    	pool->Val = 0;
    	return pool;
    }
    inline Node *build(int L,int R)
    {
    	Node *u = New();
    	if(L == R){
    		u->ls = u->rs = 0;
    		u->Val = 0;
    	}
    	else{
    		int mid = L + R >> 1;
    		u->ls = build(L,mid);
    		u->rs = build(mid+1,R);
    	}
    	return u;
    }
    inline void upd(Node *u,Node *pr,int l,int r,int pos,int x)
    {
    	*u = *pr;
    	if(l == r){
    		u->Val = x;
    		return;
    	}
    	int mid = l + r >> 1;
    	if(pos <= mid) upd(u->ls=New(),pr->ls,l,mid,pos,x);
    	else upd(u->rs=New(),pr->rs,mid+1,r,pos,x);
    	u->Val = (u->ls->Val * p[r-mid]) + u->rs->Val;
    }
    inline u64 query(Node *u,int l,int r,int L,int R)
    {
    	if(L <= l && r <= R){
    		return u->Val;
    	}
    	if(r < L || R < l) return 0;
    	int mid = l + r >> 1;
    	if(R <= mid) return query(u->ls,l,mid,L,R);
    	else if(mid+1 <= L) return query(u->rs,mid+1,r,L,R);
    	else return query(u->ls,l,mid,L,mid) * p[R-mid] + query(u->rs,mid+1,r,mid+1,R);
    }
    inline int Lcp(int u,int v)
    {
    	if(u == v) return n-u+1;
    	if(v < u) swap (u,v);
    	int l=0,r = n-v,ans(-1);
    	while(l <= r)
    	{
    		int mid = l + r >> 1;
    		if(query(rot[u],1,n,u,u+mid) == query(rot[v],1,n,v,v+mid)){
    			l = mid + 1;
    			ans = mid;
    		}
    		else r = mid - 1;
    	}
    	return ans+1;
    }
    inline int Get_(Node *u,int pos)
    {
    	if(pos > n) return -1;
    	else return query(u,1,n,pos,pos);
    }
    inline bool cmp(int u,int v)
    {
    	int len = Lcp(u,v);
    	return Get_(rot[u],u+len) < Get_(rot[v],v+len);
    }
    inline void Clr()
    {
    	for(int i=1;i <= n;i ++) bac[i] = 0,rot[i] = 0;
    	pool = mem;
    }
    
    signed  main()
    {
    	int V = 5e4;
    	p[0] = 1;
    	for(int i=1;i <= V; i ++) p[i] = p[i-1] * base;
    	while(Clr(),scanf("%d",&n)!=EOF)
    	{
    		for(int i=1;i <= n;i ++) read(a[i]);
    		rot[n] = build(1,n);
    		bac[a[n]] = n;
    		for(int i=n-1;i >= 1;i --)
    		{
    			if(bac[a[i]]) upd(rot[i]=New(),rot[i + 1],1,n,bac[a[i]],bac[a[i]]-i);
    			else rot[i] = rot[i + 1];
    			bac[a[i]]=i;
    		}
    		for(int i=1;i <= n;i ++) sa[i] = i;
    		sort(sa + 1,sa + 1 + n,cmp);	
    		u64 Ans = 1ull * n * (n + 1)/2;
    		for(int i=2;i <= n;i ++) Ans -= Lcp(sa[i],sa[i-1]);
    		printf("%llu
    ",Ans);
    	}
     }
    

    贴上这份只能得 (60pts) 的代码

  • 相关阅读:
    模型层之多表操作
    模型层:表单操作
    Django模板层
    第六十课、数组类模板
    第五十九课、类模板的深度剖析
    第五十八课、类模板的概念和意义
    第五十七课、深入理解函数模板
    第五十六课、函数模板的概念和意义
    第五十五课、经典问题解析四
    第五十四课、被遗弃的多重继承(下)
  • 原文地址:https://www.cnblogs.com/-Iris-/p/15495865.html
Copyright © 2011-2022 走看看