• BZOJ3790. 神奇项链


    处理出原串中每个点为中点的极长回文串,这个用hash或者manacher均可,反正这里不是复杂度瓶颈:(。那么问题就变成了可重叠的线段覆盖问题。
    (f[i]) 表示已经完全覆盖 (1-i) 的最小代价
    那么取结束点在i的线段([l,r](r == i))
    (f[i] = min{f[k] + 1} (l - 1 leq k < r))
    用bit维护后缀(min)即可

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef unsigned int uint;
    const int N = 100010;
    const uint base = 13131;
    
    char s[N];
    uint h[N], pw[N], g[N];
    int p[N], f[N], cnt, n;
    struct Node {int l, r;} a[N];
    struct bit {
    	int c[N];
    	#define lowbit(i) (i & -i)
    	void clear() {
    		memset(c, 0x3f, sizeof(c));
    	}
    	void add(int x, int v) {
    		for(int i = x; i; i -= lowbit(i)) c[i] = min(c[i], v);
    	}
    	int query(int x) {
    		int ans = 0x3f3f3f3f;
    		for(int i = x; i <= n + 1; i += lowbit(i)) ans = min(ans, c[i]);
    		return ans;
    	}
    } t;
    
    uint gethash(int l, int r) {
    	return h[r] - h[l - 1] * pw[r - l + 1];
    }
    uint getghash(int l, int r) {
    	return g[l] - g[r + 1] * pw[r - l + 1];
    }
    
    bool check(int l, int r) {
    	return gethash(l, r) == getghash(l, r);
    }
    
    bool operator < (Node a, Node b) {
    	return a.r < b.r;
    }
    
    int solve() {
    	t.clear();
    	memset(f, 0x3f, sizeof(f));
    	sort(a + 1, a + cnt + 1);
    	int cur = 1;
    	t.add(1, 0);
    	for(int i = 1; i <= n; ++i) {
    		while(cur <= cnt && a[cur].r <= i) f[i] = min(f[i], t.query(a[cur++].l) + 1);
    		t.add(i + 1, f[i]);
    	}
    	return f[n] - 1;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
    freopen("data.in","r",stdin);
    #endif	
    	while(~scanf("%s", s + 1)) {
    		n = strlen(s + 1);
    		pw[0] = 1;
    		h[0] = g[n + 1] = 0;
    		for(int i = 1; i <= n; ++i) {
    			h[i] = h[i - 1] * base + s[i];
    			pw[i] = pw[i - 1] * base;
    		}
    		for(int i = n; i; --i) g[i] = g[i + 1] * base + s[i];
    		cnt = 0;
    		for(int i = 1; i <= n; ++i) {
    			p[i] = 0;
    			int l = 1, r = min(i - 1, n - i);
    			while(l <= r) {
    				int mid = (l + r) >> 1;
    				if(check(i - mid, i + mid)) l = mid + 1, p[i] = mid;
    				else r = mid - 1;
    			}
    			a[++cnt] = (Node) {i - p[i], i + p[i]};
    			p[i] = 0;
    			l = 0, r = min(i, n - i);
    			while(l <= r) {
    				int mid = (l + r) >> 1;
    				if(check(i - mid + 1, i + mid)) l = mid + 1, p[i] = mid;
    				else r = mid - 1;
    			}
    			if(p[i]) a[++cnt] = (Node) {i - p[i] + 1, i + p[i]};
    		}
    		printf("%d
    ", solve());
    	}
    }
    /*
    处理出原串中每个点为中点的极长回文串,那么问题就变成了可重叠的线段覆盖问题。
    设 $f[i]$ 表示已经完全覆盖 $1-i$ 的最小代价
    那么取结束点在i的线段[l,r](r == i)
    f[i] = min{f[k] + 1} (l - 1 <= k < r)
    用bit维护后缀min即可
    */
    
  • 相关阅读:
    一些常用的方法(1)--去除DataTable中的重复数据
    皕杰报表入门知识(1)
    Red Hat 6.0 Linux系统跳过登录界面直接进入系统
    解决pycharm无法获取安装包文件列表
    sqlalchemy创建数据库自动映射
    python3使用importlib来重复加载模块
    python3使用exec来动态加载模块
    中间件datasnap用流传递数据
    使用fdmemTable来代替clientDataset,解决MySQL5.6(含)以上版本用cds多次更新时的错误
    dxSpreadSheet动态切换Sheet
  • 原文地址:https://www.cnblogs.com/henry-1202/p/11818755.html
Copyright © 2020-2023  润新知