【尺取或dp】codeforces C. An impassioned circulation of affection

http://codeforces.com/contest/814/problem/C

【题意】

给定一个长度为n的字符串s,一共有q个查询,每个查询给出一个数字m和一个字符ch,你的操作是可以改变字符串中的某些字母,最多改变m个,问操作后只包含字符ch的连续子序列最长是多少?

【思路】

方法一:

有这么一类问题,需要在给的一组数据中找到不大于某一个上限的“最优连续子序列”

于是就有了这样一种方法,找这个子序列的过程很像毛毛虫爬行方式比较流行的叫法是“尺取法”。

有关尺取的练习:

http://blog.csdn.net/acmer_sly/article/details/59524223

http://acm.hdu.edu.cn/showproblem.php?pid=5328

尺取是线性的,所以总的时间复杂度是O(qn).

方法二:
dp,对每个字母预处理,时间复杂度是O(26n^2)。

【Accepted】

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <cmath>
 4 #include <vector>
 5 #include <algorithm>
 6 #include <set>
 7 #include <map>
 8 #include <queue>
 9 #include <deque>
10 #include <stack>
11 #include <string>
12 #include <bitset>
13 #include <ctime>
14 #include<algorithm>
15 #include<cstring>
16 using namespace std;
17 typedef long long ll;
18 const int maxn=1502;
19 int n,q,m;
20 char s[maxn];
21 char ch[5];
22 
23 
24 int solve(char c)
25 {
26     //双指针 
27     int l=0,r=0;
28     int ans=0;
29     int cnt=0;
30     while(l<n&&r<n)
31     {
32         //右端点不断往后扫,直到不能再向右 
33         while(r<n && (s[r]==c||cnt<m))
34         {
35             if(s[r]!=c)
36             {
37                 cnt++;
38             }
39             r++;
40         }
41         //记下当前l下的解 
42         ans=max(ans,r-l);
43         while(l<=r && s[l]==c)
44         {
45             l++;
46         }
47         //找到第一个使cnt-1的l,r才能继续向右更新 
48         l++;
49         cnt--;
50     }
51     return ans;
52 }
53 int main()
54 {
55     while(~scanf("%d",&n))
56     {
57         scanf("%s",s);
58         scanf("%d",&q);
59         for(int i=0;i<q;i++)
60         {
61             scanf("%d%s",&m,ch);
62             int ans=solve(ch[0]);
63             printf("%d\n",ans);
64         }
65     }
66     return 0;
67  } 
尺取
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <cmath>
 4 #include <vector>
 5 #include <algorithm>
 6 #include <set>
 7 #include <map>
 8 #include <queue>
 9 #include <deque>
10 #include <stack>
11 #include <string>
12 #include <bitset>
13 #include <ctime>
14 #include<algorithm>
15 #include<cstring>
16 using namespace std;
17 typedef long long ll;
18 int n,q,m;
19 const int maxn=1502;
20 char s[maxn];
21 int dp[maxn][27];
22 char ch[5];
23 void Init()
24 {
25     memset(dp,-1,sizeof(dp));
26     for(int c=0;c<26;c++)
27     {
28         for(int i=0;i<n;i++)
29         {
30             int num=0;
31             for(int k=i;k>=0;k--)
32             {
33                 if(s[k]==(char)(c+'a'))    
34                 {
35                     num++;
36                 }
37                 //替换i-k+1-num个字母达到的子段长度是i-k+1,枚举所有的子段不断更新,找到最大值,共n^2个子段。 
38                 dp[i-k+1-num][c]=max(dp[i-k+1-num][c],i-k+1);
39             }
40         }
41     }
42 }
43 int main()
44 {
45     while(~scanf("%d",&n))
46     {
47         scanf("%s",s);
48         Init();
49         scanf("%d",&q);
50         for(int i=0;i<q;i++)
51         {
52             scanf("%d%s",&m,&ch);
53             if(dp[m][ch[0]-'a']==-1)
54             {
55                 printf("%d\n",n);
56             }
57             else
58             {
59                 printf("%d\n",dp[m][ch[0]-'a']);
60             }
61         }
62     }
63     return 0;
64 }
dp

 

posted @ 2017-06-08 16:05  shulin15  阅读(194)  评论(0编辑  收藏  举报