zoukankan      html  css  js  c++  java
  • CF750E New Year and Old Subsequence

    讲道理好久没有做过题了..


    题目大意

    给出长度为$n$的只含数字的串,有$q$个询问,每次询问一段区间,问最少删去多少个数才能变成只含2017子序列而不含2016子序列


    吉爸爸好强啊..

    定义$a_{i,j}$表示该区间从第$i$位匹配不了第$j$位最少要删去的数字数

    这个东西用一个线段树或者st表来维护,合并是类似于矩阵乘法的..

    根据吉爸爸的优化,对于一个询问区间$[l,r]$

    因为一定需要一个7,所以把它分成两段,就像这样

    l...最后一个7...r

    那么前面一段只需要求出从第一位但是匹配不了最后一位的方案数,再加上后面那一段6的个数就是答案了..


     

    code

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    const int Maxn = 200010;
    const int lg = 20;
    const int inf = 0x7fffffff;
    struct node {
    	int a[4][4];
    	void clear (){ memset ( a, 63, sizeof (a) ); }
    }f[Maxn][lg], p;
    int n, m;
    char s[Maxn];
    int bit[Maxn], pre[Maxn], sum[Maxn];
    int _min ( int x, int y ){ return x < y ? x : y; }
    void merge ( node &ret, node x, node y ){
    	ret.clear ();
    	int i, j, k;
    	for ( i = 0; i < 4; i ++ ) for ( j = 0; j < 4; j ++ ) for ( k = 0; k < 4; k ++ ) ret.a[i][j] = _min ( x.a[i][k]+y.a[k][j], ret.a[i][j] );
    }
    int getans ( int l, int r ){
    	int len = r-l+1;
    	p.clear ();
    	p.a[0][0] = p.a[1][1] = p.a[2][2] = p.a[3][3] = 0;
    	while ( len > 0 ){
    		merge ( p, p, f[l][bit[len]] );
    		l += (1<<bit[len]);
    		len -= (1<<bit[len]);
    	}
    	return p.a[0][3];
    }
    int main (){
    	int i, j, k;
    	scanf ( "%d%d", &n, &m );
    	scanf ( "%s", s+1 );
    	bit[1] = 0;
    	for ( i = 2; i <= n; i ++ ) bit[i] = bit[i>>1]+1;
    	for ( i = 1; i <= n; i ++ ){
    		if ( s[i] == '6' ) sum[i] = sum[i-1]+1; else sum[i] = sum[i-1];
    		if ( s[i] == '7' ) pre[i] = i; else pre[i] = pre[i-1];
    	}
    	for ( i = 1; i <= n; i ++ ){
    		f[i][0].clear ();
    		f[i][0].a[0][0] = f[i][0].a[1][1] = f[i][0].a[2][2] = f[i][0].a[3][3] = 0;
    		if ( s[i] == '2' ) f[i][0].a[0][1] = 0, f[i][0].a[0][0] = 1;
    		if ( s[i] == '0' ) f[i][0].a[1][2] = 0, f[i][0].a[1][1] = 1;
    		if ( s[i] == '1' ) f[i][0].a[2][3] = 0, f[i][0].a[2][2] = 1;
    		if ( s[i] == '6' ) f[i][0].a[3][3] = 1;
    	}
    	for ( i = n; i >= 1; i -- ){
    		for ( j = 1; j <= 18 && i+(1<<(j-1)) <= n; j ++ ){
    			merge ( f[i][j], f[i][j-1], f[i+(1<<(j-1))][j-1] );
    		}
    	}
    	for ( i = 1; i <= m; i ++ ){
    		int l, r;
    		scanf ( "%d%d", &l, &r );
    		k = pre[r];
    		int ans = getans ( l, k-1 );
    		if ( ans > n ) printf ( "-1
    " );
    		else printf ( "%d
    ", ans+sum[r]-sum[k] );
    	}
    	return 0;
    }
    

    哎好久没打都有点生疏了.. 加油吧..

  • 相关阅读:
    mysql delete 不支持表别名
    查找应用编译时所找的动态库:LD_DEBUG
    ng
    linux 开机启动自动执行某用户的脚步、程序
    理解Linux系统中的load average(图文版)
    char指针与数组(转载)
    堆 栈 静态区
    linux下which、whereis、locate、find 命令的区别
    linux c动态库编译好了,不能用。有些方法报(undefined reference)错误。
    浅谈管理系统操作日志设计(附操作日志类)
  • 原文地址:https://www.cnblogs.com/darklove/p/6248424.html
Copyright © 2011-2022 走看看