• P5161 WD与数列 [后缀自动机,线段树合并,启发式合并]


    考虑选一对(A),(B),使得 (A_i - B_i = A_j - B_j)(|A| = |B|)
    (A),(B) 不相交,否则就是 (sum LCP(i,j))
    然后转化成 (A_i - A_j = B_i - B_j) 然后令 (j = i - 1) 丢到 (SAM) 里。

    我们考虑分类讨论,先考虑不相交的,答案直接加上。

    ans1 表示 (endpos) 的数量。
    ans2 表示 ([i]) 所对应的节点包含的子串的最后一个点 (i)

    ans1 = ans2 = 0; smt.qry(rt[u], x + 1 + len[u], n - 1, 1, n - 1);
    ans += ans1 * len[u];
    ans1 = ans2 = 0; smt.qry(rt[u], 1, x - len[u] - 1, 1, n - 1);
    ans += ans1 * len[u];
    

    考虑相交的部分。

    ans1 = ans2 = 0; smt.qry(rt[u], x - len[u], x - 1, 1, n - 1);
    ans += ans1 * (x - 1) - ans2;
    ans1 = ans2 = 0; smt.qry(rt[u], x + 1, x + len[u], 1, n - 1);
    ans += ans2 - ans1 * (x + 1);
    

    这样就好了。

    // clang-format off
    // powered by c++11
    // by Isaunoya
    #pragma GCC optimize(3)
    #pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
    #include <tr1/unordered_map>
    #include<bits/stdc++.h>
    #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
    #define Rep(i,x,y) for(register int i=(x);i>=(y);--i)
    using namespace std;using db=double;using ll=long long;
    using uint=unsigned int;using ull=unsigned long long;
    using pii=pair<int,int>;
    #define Tp template
    #define fir first
    #define sec second
    Tp<class T>void cmax(T&x,const T&y){if(x<y)x=y;}Tp<class T>void cmin(T&x,const T&y){if(x>y)x=y;}
    #define all(v) v.begin(),v.end()
    #define sz(v) ((int)v.size())
    #define pb emplace_back
    Tp<class T>void sort(vector<T>&v){sort(all(v));}Tp<class T>void reverse(vector<T>&v){reverse(all(v));}
    Tp<class T>void unique(vector<T>&v){sort(all(v)),v.erase(unique(all(v)),v.end());}inline void reverse(string&s){reverse(s.begin(),s.end());}
    const int SZ=1<<23|233;
    struct FILEIN{char qwq[SZ],*S=qwq,*T=qwq,ch;
    #ifdef __WIN64
    #define GETC getchar
    #else
    inline char GETC(){return(S==T)&&(T=(S=qwq)+fread(qwq,1,SZ,stdin),S==T)?EOF:*S++;}
    #endif
    inline FILEIN&operator>>(char&c){while(isspace(c=GETC()));return*this;}inline FILEIN&operator>>(string&s){s.clear();while(isspace(ch=GETC()));if(!~ch)return*this;s=ch;while(!isspace(ch=GETC())&&~ch)s+=ch;return*this;}
    inline FILEIN&operator>>(char*str){char*cur=str;while(*cur)*cur++=0;cur=str;while(isspace(ch=GETC()));if(!~ch)return*this;*cur=ch;while(!isspace(ch=GETC())&&~ch)*++cur=ch;*++cur=0;return*this;}
    Tp<class T>inline void read(T&x){bool f=0;while((ch=GETC())<48&&~ch)f^=(ch==45);x=~ch?(ch^48):0;while((ch=GETC())>47)x=x*10+(ch^48);x=f?-x:x;}
    inline FILEIN&operator>>(int&x){return read(x),*this;}inline FILEIN&operator>>(ll&x){return read(x),*this;}inline FILEIN&operator>>(uint&x){return read(x),*this;}inline FILEIN&operator>>(ull&x){return read(x),*this;}
    inline FILEIN&operator>>(double&x){read(x);bool f=x<0;x=f?-x:x;if(ch^'.')return*this;double d=0.1;while((ch=GETC())>47)x+=d*(ch^48),d*=.1;return x=f?-x:x,*this;}
    }in;
    struct FILEOUT{const static int LIMIT=1<<22;char quq[SZ],ST[233];int sz,O,pw[233];
    FILEOUT(){set(7);rep(i,pw[0]=1,9)pw[i]=pw[i-1]*10;}~FILEOUT(){flush();}
    inline void flush(){fwrite(quq,1,O,stdout),fflush(stdout),O=0;}
    inline FILEOUT&operator<<(char c){return quq[O++]=c,*this;}inline FILEOUT&operator<<(string str){if(O>LIMIT)flush();for(char c:str)quq[O++]=c;return*this;}
    inline FILEOUT&operator<<(char*str){if(O>LIMIT)flush();char*cur=str;while(*cur)quq[O++]=(*cur++);return*this;}
    Tp<class T>void write(T x){if(O>LIMIT)flush();if(x<0){quq[O++]=45;x=-x;}do{ST[++sz]=x%10^48;x/=10;}while(x);while(sz)quq[O++]=ST[sz--];}
    inline FILEOUT&operator<<(int x){return write(x),*this;}inline FILEOUT&operator<<(ll x){return write(x),*this;}inline FILEOUT&operator<<(uint x){return write(x),*this;}inline FILEOUT&operator<<(ull x){return write(x),*this;}
    int len,lft,rig;void set(int l){len=l;}inline FILEOUT&operator<<(double x){bool f=x<0;x=f?-x:x,lft=x,rig=1.*(x-lft)*pw[len];return write(f?-lft:lft),quq[O++]='.',write(rig),*this;}
    }out;
    #define int long long
    struct Math{
    vector<int>fac,inv;int mod;
    void set(int n,int Mod){fac.resize(n+1),inv.resize(n+1),mod=Mod;rep(i,fac[0]=1,n)fac[i]=fac[i-1]*i%mod;inv[n]=qpow(fac[n],mod-2);Rep(i,n-1,0)inv[i]=inv[i+1]*(i+1)%mod;}
    int qpow(int x,int y){int ans=1;for(;y;y>>=1,x=x*x%mod)if(y&1)ans=ans*x%mod;return ans;}int C(int n,int m){if(n<0||m<0||n<m)return 0;return fac[n]*inv[m]%mod*inv[n-m]%mod;}
    int gcd(int x,int y){return!y?x:gcd(y,x%y);}int lcm(int x,int y){return x*y/gcd(x,y);}
    }math;
    // clang-format on
    
    int n;
    const int maxn = 6e5 + 56;
    int a[maxn], rt[maxn];
    int ans1, ans2;
    
    struct SegMentTree {
    	int cnt;
    	
    	SegMentTree() {
    		cnt = 0;
    	}
    	
    	int ls[maxn << 5], rs[maxn << 5];
    	int c[maxn << 5], v[maxn << 5];
    	
    	void upd(int &p , int l , int r , int x) {
    		if(! p) 
    			p = ++ cnt;
    		c[p] ++, v[p] += x;
    		if(l == r) return;
    		
    		int mid = l + r >> 1;
    		if(x <= mid)
    			upd(ls[p], l, mid, x);
    		else
    			upd(rs[p], mid + 1, r, x);
    	}
    	
    	int merge(int x, int y, int l, int r) {
    		if(! x || ! y) return x | y;
    		if(l == r) {
    			c[x] += c[y];
    			v[x] += v[y];
    			return x;
    		}
    		int mid = l + r >> 1;
    		ls[x] = merge(ls[x], ls[y], l, mid);
    		rs[x] = merge(rs[x], rs[y], mid + 1, r);
    		c[x] = c[ls[x]] + c[rs[x]];
    		v[x] = v[ls[x]] + v[rs[x]];
    		return x;
    	}
    	
    	void qry(int p, int a, int b, int l, int r) {
    		if(a > b) return;
    		if(! p) return;
    		if(a <= l && r <= b) {
    			ans1 += c[p];
    			ans2 += v[p];
    			return;
    		}
    		int mid = l + r >> 1;
    		if(a <= mid)
    			qry(ls[p], a, b, l , mid);
    		if(b > mid)
    			qry(rs[p], a, b, mid + 1, r);
    	}
    } smt;
    
    int ans = 0;
    struct suffix_auto_maton {
    	int las, cnt;
    	
    	suffix_auto_maton() { las = cnt = 1; }
    	
    	unordered_map <int , int> ch[maxn];
    	int fa[maxn], len[maxn];
    	vector < int > qwq[maxn];
    	
    	void ins(int c , int id) {
    		int p = las, np = las = ++ cnt;
    		len[np] = len[p] + 1;
    		qwq[np].push_back(id);
    		smt.upd(rt[np], 1, n - 1, id);
    		for(; p && !ch[p][c]; p = fa[p])
    			ch[p][c] = np;
    		if(! p) {
    			fa[np] = 1;
    		} else {
    			int q = ch[p][c];
    			if(len[q] == len[p] + 1) {
    				fa[np] = q;
    			} else {
    				int nq = ++ cnt;
    				ch[nq] = ch[q];
    				fa[nq] = fa[q], fa[q] = fa[np] = nq;
    				len[nq] = len[p] + 1;
    				for(; p && ch[p][c] == q; p = fa[p])
    					ch[p][c] = nq;
    			}
    		}
    	}
    		
    	vector < int > g[maxn];
    	
    	void build() {
    		rep(i, 2, cnt) g[fa[i]].pb(i);
    	}
    	
    	void merge(int u , int v) {
    		if(sz(qwq[u]) < sz(qwq[v])) {
    			swap(qwq[u], qwq[v]);
    			swap(rt[u], rt[v]);
    		}
    		
    		for(auto x : qwq[v]) {
    			ans1 = ans2 = 0; smt.qry(rt[u], x + 1 + len[u], n - 1, 1, n - 1);
    			ans += ans1 * len[u];
    			ans1 = ans2 = 0; smt.qry(rt[u], 1, x - len[u] - 1, 1, n - 1);
    			ans += ans1 * len[u];
    			ans1 = ans2 = 0; smt.qry(rt[u], x - len[u], x - 1, 1, n - 1);
    			ans += ans1 * (x - 1) - ans2;
    			ans1 = ans2 = 0; smt.qry(rt[u], x + 1, x + len[u], 1, n - 1);
    			ans += ans2 - ans1 * (x + 1);
    			qwq[u].pb(x);
    		}
    		
    		rt[u] = smt.merge(rt[u], rt[v], 1 , n - 1);
    	}
    	
    	void dfs(int u) {
    		for(int v : g[u]) {
    			dfs(v);
    			merge(u , v);
    		}
    	}
    	
    } sam;
    
    signed main(){
    	//code begin.
    	in >> n;
    	rep(i , 1 , n) in >> a[i];
    	rep(i , 1 , n - 1)
    		sam.ins(a[i + 1] - a[i], i);
    	sam.build(), sam.dfs(1);
    	ans += (n - 1) * n / 2;
    	out << ans << '
    ';
    	return 0;
    	//code end.
    }
    
  • 相关阅读:
    楷书四大家
    什么叫同学?
    css悬浮在页面顶端
    jq给页面添加覆盖层遮罩的实例
    jQuery实现遮罩层
    jQuery实现的文字逐行向上间歇滚动效果示例
    jquery实现文字由下到上循环滚动的实例代码
    Js/Jquery获取网页屏幕可见区域高度
    本机无法访问虚拟机配置的域名
    thinkphp5+GatewayWorker+Workerman
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/12569180.html
Copyright © 2020-2023  润新知