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\n" ); else printf ( "%d\n", ans+sum[r]-sum[k] ); } return 0; }
哎好久没打都有点生疏了.. 加油吧..
作者:Ra1nbow
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。