zoukankan      html  css  js  c++  java
  • BZOJ 4698: [SDOI2008]Sandy的卡片

    题面

    有权限号的去看吧
    Luogu

    Sol

    差分后就是求多个串的最长公共子串
    套路啊
    拼在一起用不同字符隔开,后缀数组,二分答案,分块height,开桶记录即可
    我把差分值离散了

    # include <bits/stdc++.h>
    # define IL inline
    # define RG register
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    const int _(2000000);
    
    IL ll Read(){
        RG char c = getchar(); RG ll x = 0, z = 1;
        for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        return x * z;
    }
    
    int T, n, a[_], sa[_], rk[_], tmp[_], height[_], t[_], ans, mx, vis[_], cnt[1010], Index;
    int o[_], num[1010][1010], len, l[_];
     
    IL bool Cmp(RG int i, RG int j, RG int k){  return tmp[i] == tmp[j] && tmp[i + k] == tmp[j + k];  }
    
    IL void Suffix_Sort(){
        RG int m = mx;
        for(RG int i = 1; i <= n; ++i) ++t[rk[i] = a[i]];
        for(RG int i = 1; i <= m; ++i) t[i] += t[i - 1];
        for(RG int i = n; i; --i) sa[t[rk[i]]--] = i;
        for(RG int k = 1; k <= n; k <<= 1){
            RG int l = 0;
            for(RG int i = n - k + 1; i <= n; ++i) tmp[++l] = i;
            for(RG int i = 1; i <= n; ++i) if(sa[i] > k) tmp[++l] = sa[i] - k;
            for(RG int i = 0; i <= m; ++i) t[i] = 0;
            for(RG int i = 1; i <= n; ++i) ++t[rk[tmp[i]]];
            for(RG int i = 1; i <= m; ++i) t[i] += t[i - 1];
            for(RG int i = n; i; --i) sa[t[rk[tmp[i]]]--] = tmp[i];
            swap(rk, tmp); rk[sa[1]] = l = 1;
            for(RG int i = 2; i <= n; ++i) rk[sa[i]] = Cmp(sa[i - 1], sa[i], k) ? l : ++l;
            if(l >= n) break; m = l;
        }
        for(RG int i = 1, h = 0; i <= n; ++i){
    		if(h) --h;
            while(a[i + h] == a[sa[rk[i] - 1] + h]) ++h;
    		height[rk[i]] = h;
        }
    }
    
    IL bool Check(RG int x){
    	RG int tot = (vis[sa[1]] != 0); cnt[vis[sa[1]]] = ++Index;
    	for(RG int i = 2; i <= n; ++i){
    		if(height[i] >= x){
    			if(cnt[vis[sa[i]]] != Index) tot += (vis[sa[i]] != 0), cnt[vis[sa[i]]] = Index;
    		}
    		else cnt[vis[sa[i]]] = ++Index, tot = (vis[sa[i]] != 0);
    		if(tot == T) return 1;
    	}
    	return 0;
    }
    
    int main(RG int argc, RG char* argv[]){
    	T = Read();
    	for(RG int i = 1; i <= T; ++i){
    		l[i] = Read();
    		for(RG int j = 1; j <= l[i]; ++j) num[i][j] = Read();
    	}
    	for(RG int i = 1; i <= T; ++i)
    		for(RG int j = 1; j <= l[i]; ++j) o[++len] = num[i][j] = num[i][j + 1] - num[i][j];
    	sort(o + 1, o + len + 1); len = unique(o + 1, o + len + 1) - o - 1;
    	mx = len;
    	for(RG int i = 1; i <= T; ++i){
    		for(RG int j = 1; j <= l[i]; ++j){
    			num[i][j] = lower_bound(o + 1, o + len + 1, num[i][j]) - o;
    			a[++n] = num[i][j]; vis[n] = i;
    		}
    		a[++n] = ++mx;
    	}
    	Suffix_Sort();
    	Check(1);
    	RG int l = 0, r = n;
    	while(l <= r){
    		RG int mid = (l + r) >> 1;
    		if(Check(mid)) ans = mid + 1, l = mid + 1;
    		else r = mid - 1;
    	}
    	printf("%d
    ", ans);
        return 0;
    }
    
    
  • 相关阅读:
    BZOJ 2034 【2009国家集训队】 最大收益
    vijos P1780 【NOIP2012】 开车旅行
    BZOJ 2115 【WC2011】 Xor
    BZOJ 3631 【JLOI2014】 松鼠的新家
    BZOJ 4717 改装
    BZOJ 2957 楼房重建
    BZOJ 4034 【HAOI2015】 T2
    BZOJ 1834 【ZJOI2010】 network 网络扩容
    BZOJ 2440 【中山市选2011】 完全平方数
    BZOJ 2733 【HNOI2012】 永无乡
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8350093.html
Copyright © 2011-2022 走看看