您的位置:首页 > Web前端

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

2017-06-08 16:05 369 查看
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 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: