A digital string is "good": when it contains a subsequence 91029102 and does not contain a subsequence 81028102.
The bad value of a string is defined as how many characters are to remove at least, so that the string satisfies the "good" property. Output -1
if the string cannot satisfy the "good" property by removing some characters (0 or maybe more).
The first line contains two integers n, Qn,Q(1\leq n,Q\leq2*10^5)(1≤n,Q≤2∗105). Where nn is the length of the string and QQ is the number of queries.
The second line contains a string ss that consists entirely of decimal numbers.
The next QQ line, each line contains two integers l, rl,r(1\leq l\leq r\leq n)(1≤l≤r≤n), denoting a query.
For each query, output an answer which is the bad value of the substring s_ls_{l+1} \cdots s_rslsl+1⋯sr from ss.
样例输入复制
8 3 88988102 1 8 2 8 1 7
样例输出复制
4 3 -1
给了一个长度为N的字符串,Q次询问,要求区间[L,R]最少要删除多少个字符保证字符串只会出现像“9102”这样的序列,不会出现“8102”这样的序列。
这道题是CF 750E原题,虽然是原题,但是思路却从没见过。非常值得记录下来。
我们设置了5个状态。
0表示初始状态,1表示只有“2”,2表示只有“20”,3表示只有“201”,4表示只有“2019”这四个状态。
然后构造一个5x5的矩阵,dp[i][j]表示的是从i状态到j状态的最小花费。
所以最后只要知道查询区间的dp[0][4]的值是多少就行了。
而这件事可以用线段树来做。
而在这里面的矩阵运算是把乘法改成了加法取min,这样类似floyd求最短路。
而对于矩阵的每一个状态的转移,在构建线段树的时候处理好就行了。
具体处理看代码就会明白了。
#include
using namespace std;
const int maxn=2e5+5;
const int inf=0x3f3f3f3f;
char a[maxn];
struct node
{
int dp[5][5];
void init(){
memset(dp,inf,sizeof(dp));
for(int i=0;i<5;i++) dp[i][i]=0;
}
friend node operator * (node a,node b){
node tmp;//tmp.init();
memset(tmp.dp,inf,sizeof(tmp.dp));
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
for(int k=0;k<5;k++){
tmp.dp[i][j]=min(tmp.dp[i][j],a.dp[i][k]+b.dp[k][j]);
}
}
}
return tmp;
}
}tr[maxn<<2];
void build(int i,int l,int r)
{
if(l==r)
{
tr[i].init();
int c=a[l]-'0';
if(c==2) tr[i].dp[0][0]=1,tr[i].dp[0][1]=0;
if(c==0) tr[i].dp[1][1]=1,tr[i].dp[1][2]=0;
if(c==1) tr[i].dp[2][2]=1,tr[i].dp[2][3]=0;
if(c==9) tr[i].dp[3][3]=1,tr[i].dp[3][4]=0;
if(c==8) tr[i].dp[3][3]=1,tr[i].dp[4][4]=1;
return;
}
int mid=(l+r)>>1;
build(2*i,l,mid);
build(2*i+1,mid+1,r);
tr[i]=tr[2*i]*tr[2*i+1];
}
node query(int i,int l,int r,int x,int y)
{
node ans;
ans.init();
if(x<=l&&r<=y) return tr[i];
int mid=(l+r)>>1;
if(x<=mid) ans=ans*query(2*i,l,mid,x,y);
if(y>mid) ans=ans*query(2*i+1,mid+1,r,x,y);
return ans;
}
int main()
{
int n,q,l,r;
scanf("%d%d",&n,&q);
scanf("%s",a+1);
reverse(a+1,a+1+n);
build(1,1,n);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&l,&r);
l=n+1-l;
r=n+1-r;
int ans=query(1,1,n,r,l).dp[0][4];
printf("%d\n",ans==inf?-1:ans);
}
return 0;
}