2019南昌网络赛 hello 2019
这道题和一道2017,2016的类似。
A string t is called nice if a string “2017” occurs in t as a subsequence but a string “2016” doesn’t occur in t as a subsequence. For example, strings “203434107” and “9220617” are nice, while strings “20016”, “1234” and “20167” aren’t nice.
The ugliness of a string is the minimum possible number of characters to remove, in order to obtain a nice string. If it’s impossible to make a string nice by removing characters, its ugliness is - 1.
Limak has a string s of length n, with characters indexed 1 through n. He asks you q queries. In the i-th query you should compute and print the ugliness of a substring (continuous subsequence) of s starting at the index ai and ending at the index bi (inclusive).
Input
The first line of the input contains two integers n and q (4 ≤ n ≤ 200 000, 1 ≤ q ≤ 200 000) — the length of the string s and the number of queries respectively.
The second line contains a string s of length n. Every character is one of digits ‘0’–‘9’.
The i-th of next q lines contains two integers ai and bi (1 ≤ ai ≤ bi ≤ n), describing a substring in the i-th query.
Output
For each query print the ugliness of the given substring.
Examples
Input
8 3
20166766
1 8
1 7
2 8
Output
4
3
-1
Input
15 5
012016662091670
3 4
1 14
4 15
1 13
10 15
Output
-1
2
1
-1
-1
Input
4 2
1234
2 4
1 2
Output
-1
-1
Note
In the first sample:
In the first query, ugliness(“20166766”) = 4 because all four sixes must be removed.
In the second query, ugliness(“2016676”) = 3 because all three sixes must be removed.
In the third query, ugliness(“0166766”) = - 1 because it’s impossible to remove some digits to get a nice string.
In the second sample:
In the second query, ugliness(“01201666209167”) = 2. It’s optimal to remove the first digit ‘2’ and the last digit ‘6’, what gives a string “010166620917”, which is nice.
In the third query, ugliness(“016662091670”) = 1. It’s optimal to remove the last digit ‘6’, what gives a nice string “01666209170”.
要是以前做过这道题就好了。。南昌的题目和这道题换汤不换药,改改顺序就好了。。
如果是单次询问的话,就直接区间dp做就好了。但是这次是多次查询,我们就需要利用数据结构了。区间查询,线段树给上。
我们定义0,1,2,3,4为"",2,20,201,2017的状态。对于每个状态用矩阵表示:
a[i][j]代表着从状态i转移到状态j所需要花费的价值。一开始把对角线上初始化为0,其余的变为inf。
假如当前位置是2的话,那么状态转移矩阵就变为:
从"“变为2不需要花费价值,但是从”“到”“需要花费价值为1,因为保持”"需要删除2。0,1,7是一样的。
但是到6的时候,保持201到201需要删除6,花费价值为1。因为不能出现2016,所以从2017转移也需要删除一个价值。
因为要求最小价值,所以类似于floyed矩阵加法:
————————————————
版权声明:本文为CSDN博主「starlet_kiss」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/starlet_kiss/article/details/100694910
代码如下:
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define inf 0x3f3f3f3f 4 using namespace std; 5 6 const int maxx=2e5+100; 7 struct node{ 8 int a[5][5]; 9 node operator+(const node &b)const//重载加法 10 { 11 node c; 12 for(int i=0;i<5;i++) 13 { 14 for(int j=0;j<5;j++) 15 { 16 c.a[i][j]=inf; 17 for(int k=0;k<5;k++) 18 c.a[i][j]=min(c.a[i][j],a[i][k]+b.a[k][j]); 19 } 20 } 21 return c; 22 } 23 }p[maxx<<2]; 24 char s[maxx]; 25 int n,m; 26 27 inline void pushup(int cur) 28 { 29 p[cur]=p[cur<<1]+p[cur<<1|1]; 30 } 31 inline void build(int l,int r,int cur) 32 { 33 if(l==r) 34 { 35 for(int i=0;i<5;i++)for(int j=0;j<5;j++) p[cur].a[i][j]=(i==j)?0:inf; 36 if(s[l]=='2') p[cur].a[0][0]=1,p[cur].a[0][1]=0; 37 else if(s[l]=='0') p[cur].a[1][1]=1,p[cur].a[1][2]=0; 38 else if(s[l]=='1') p[cur].a[2][2]=1,p[cur].a[2][3]=0; 39 else if(s[l]=='7') p[cur].a[3][3]=1,p[cur].a[3][4]=0; 40 else if(s[l]=='6') p[cur].a[3][3]=1,p[cur].a[4][4]=1; 41 return ; 42 } 43 int mid=l+r>>1; 44 build(l,mid,cur<<1); 45 build(mid+1,r,cur<<1|1); 46 pushup(cur); 47 } 48 inline node query(int L,int R,int l,int r,int cur) 49 { 50 if(l<=L&&R<=r) return p[cur]; 51 int mid=L+R>>1; 52 if(r<=mid) return query(L,mid,l,r,cur<<1); 53 else if(l>mid) return query(mid+1,R,l,r,cur<<1|1); 54 else return query(L,mid,l,mid,cur<<1)+query(mid+1,R,mid+1,r,cur<<1|1); 55 } 56 int main() 57 { 58 int l,r; 59 while(~scanf("%d%d",&n,&m)) 60 { 61 scanf("%s",s+1); 62 build(1,n,1); 63 while(m--) 64 { 65 scanf("%d%d",&l,&r); 66 node ans=query(1,n,l,r,1); 67 if(ans.a[0][4]==inf) printf("-1\n"); 68 else printf("%d\n",ans.a[0][4]); 69 } 70 } 71 return 0; 72 } 73 ———————————————— 74 版权声明:本文为CSDN博主「starlet_kiss」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 75 原文链接:https://blog.csdn.net/starlet_kiss/article/details/100694910
南昌的这道题因为是9102和8102的区别,出现的位置是在第一个,我们把原来的字符串倒一下,把询问区间换成倒置之后的区间就好了。
代码如下:
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define inf 0x3f3f3f3f 4 using namespace std; 5 6 const int maxx=2e5+100; 7 struct node{ 8 int a[5][5]; 9 node operator+(const node &b)const 10 { 11 node c; 12 for(int i=0;i<5;i++) 13 { 14 for(int j=0;j<5;j++) 15 { 16 c.a[i][j]=inf; 17 for(int k=i;k<5;k++){ 18 if(k>j) continue; 19 c.a[i][j]=min(c.a[i][j],a[i][k]+b.a[k][j]); 20 } 21 } 22 } 23 return c; 24 } 25 }p[maxx<<2]; 26 char s[maxx],ss[maxx]; 27 int n,m; 28 29 inline void pushup(int cur) 30 { 31 p[cur]=p[cur<<1]+p[cur<<1|1]; 32 } 33 inline void build(int l,int r,int cur) 34 { 35 if(l==r) 36 { 37 for(int i=0;i<5;i++)for(int j=0;j<5;j++) p[cur].a[i][j]=(i==j)?0:inf; 38 if(s[l]=='2') p[cur].a[0][0]=1,p[cur].a[0][1]=0; 39 else if(s[l]=='0') p[cur].a[1][1]=1,p[cur].a[1][2]=0; 40 else if(s[l]=='1') p[cur].a[2][2]=1,p[cur].a[2][3]=0; 41 else if(s[l]=='9') p[cur].a[3][3]=1,p[cur].a[3][4]=0; 42 else if(s[l]=='8') p[cur].a[3][3]=1,p[cur].a[4][4]=1; 43 return ; 44 } 45 int mid=l+r>>1; 46 build(l,mid,cur<<1); 47 build(mid+1,r,cur<<1|1); 48 pushup(cur); 49 } 50 inline node query(int L,int R,int l,int r,int cur) 51 { 52 if(l<=L&&R<=r) return p[cur]; 53 int mid=L+R>>1; 54 if(r<=mid) return query(L,mid,l,r,cur<<1); 55 else if(l>mid) return query(mid+1,R,l,r,cur<<1|1); 56 else return query(L,mid,l,mid,cur<<1)+query(mid+1,R,mid+1,r,cur<<1|1); 57 } 58 int main() 59 { 60 int l,r; 61 while(~scanf("%d%d",&n,&m)) 62 { 63 scanf("%s",ss+1); 64 for(int i=1;i<=n;i++) s[i]=ss[n-i+1]; 65 build(1,n,1); 66 while(m--) 67 { 68 scanf("%d%d",&l,&r); 69 node ans=query(1,n,n-r+1,n-l+1,1); 70 if(ans.a[0][4]==inf) printf("-1\n"); 71 else printf("%d\n",ans.a[0][4]); 72 } 73 } 74 return 0; 75 }