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 }

 

posted @ 2019-09-13 10:13  古比  阅读(287)  评论(0编辑  收藏  举报