zoukankan      html  css  js  c++  java
  • Codeforces 750E 线段树DP

    题意:给你一个字符串,有两种操作:1:把某个位置的字符改变。2:询问l到r的子串最少需要删除多少个字符,使得这个子串含有2017子序列,并且没有2016子序列?

    思路:线段树上DP,我们设状态0, 1, 2, 3, 4分别为: null, 2, 20, 201, 2017的最小花费,我们用线段树来维互状态转移的花费矩阵,合并相邻的两个子串的时候直接转移即可。

    代码:

    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    #define ls (o << 1)
    #define rs (o << 1 | 1)
    using namespace std;
    const int maxn = 200010;
    int a[maxn];
    char s[maxn];
    struct node {
    	int f[5][5];
    	void init(int x) {
    		for (int i = 0; i < 5; i++) {
    			for (int j = 0; j < 5; j++) {
    				if(i == j) continue;
    				f[i][j] = INF;
    			}
    		}
    		if(x == 2) {
    			f[0][0] = 1, f[0][1] = 0;
    		} else if (x == 0) {
    			f[1][1] = 1, f[1][2] = 0;			
    		} else if (x == 1) {
    			f[2][2] = 1, f[2][3] = 0;
    		} else if (x == 7) {
    			f[3][3] = 1, f[3][4] = 0;
    		} else if (x == 6) {
    			f[3][3] = 1;
    			f[4][4] = 1;
    		} else if (x == -1){
    			for (int i = 0; i < 5; i++)
    				f[i][i] = INF;
    		} else {
    			for (int i = 0; i < 5; i++)
    				f[i][i] = 0;
    		}
    	}
    	
    	void print() {
    		for (int i = 0; i < 5; i++) {
    			for (int j = 0; j < 5; j++) {
    				if(f[i][j] == INF) printf("inf ");
    				else printf("%d ", f[i][j]);
    			}
    			printf("
    ");
    		}
    	}
    };
    node tr[maxn * 4];
    node merge(node t1, node t2) {
    	node ans;
    	ans.init(-1);
    //	ans.init(-1);
    //	printf("ans
    ");
    //	ans.print();
    //	printf("t1
    ");
    //	t1.print();
    //	printf("t2
    ");
    //	t2.print();
    	for (int i = 0; i < 5; i++) {
    		for (int j = i; j < 5; j++) {
    			for (int k = i; k <= j; k++) {
    				ans.f[i][j] = min(ans.f[i][j], t1.f[i][k] + t2.f[k][j]); 
    			}
    		}
    	}
    //	printf("ans
    ");
    //	ans.print();
    	return ans;
    }
    void build(int o, int l, int r) {
    	if(l == r) {
    		tr[o].init(a[l]);
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(ls, l, mid);
    	build(rs, mid + 1, r);
    	tr[o] = merge(tr[ls], tr[rs]);
    }
    void update(int o, int l, int r, int ql, int qr, int val) {
    	if(l == r) {
    		tr[o].init(val);
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(ql <= mid) update(ls, l, mid, ql, qr, val);
    	if(qr > mid) update(rs, mid + 1, r, ql, qr, val);
    	tr[o] = merge(tr[ls], tr[rs]);
    }
    node query(int o, int l, int r, int ql, int qr) {
    	if(l >= ql && r <= qr) {
    		return tr[o];
    	}
    	int mid = (l + r) >> 1;
    	node ans;
    	ans.init(-1);
    	if(ql <= mid && qr > mid) ans = merge(query(ls, l, mid, ql, qr), query(rs, mid + 1, r, ql, qr));
    	else if(ql <= mid) ans = query(ls, l, mid, ql, qr);
    	else if(qr > mid) ans = query(rs, mid + 1, r, ql, qr);
    	return ans; 
    }
    int main() {
    	int n, m, l, r;
    	scanf("%d%d", &n, &m);
    	scanf("%s", s + 1);
    	for (int i = 1; i <= n; i++) {
    		a[i] = s[i] - '0';
    	}
    	build(1, 1, n);
    	for (int i = 1; i <= m; i++) {
    		scanf("%d%d", &l, &r);
    		node ans = query(1, 1, n, l, r);
    		if(ans.f[0][4] == INF) printf("-1
    ");
    		else printf("%d
    ", ans.f[0][4]);
    	}
    } 
    

      

  • 相关阅读:
    通信中几种复用方式的介绍
    通信的一些基本概念整理
    网易有道2017内推选择题
    腾讯2017暑期实习生编程题
    MATLAB的一些应用--最近用的比较多
    (十六)命令模式-代码实现
    (十四)观察者模式-代码实现
    (十三)备忘录模式-代码实现
    (十二)模板模式-代码实现
    (十一)享元模式-代码实现
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/11488340.html
Copyright © 2011-2022 走看看