HDU 6345(子串查询 暴力)

题意是每组给定一个字符串,在有限查询次数内输出所要查询区间的字典序最小的子串个数。

字典序最小的子串,就是所查询区间中字典序最小的单个字符,问题就转化成了求一段区间内字典序最小的字符个数。

开始时盲目暴力,直接用桶排序的做法一段一段去求,果然t了(这种就不贴代码了)......

然后想到先扫一遍,求出从字符串首位到第 i 位的最小字符数,再用一个数组存第 0 位到第 i 位的最小字符,比较第 i 位的字符和前 i - 1 位的最小字符,第 i 位更小的话就更新最小字符和最小字符数......这样扫一遍后,问到哪个区间就比较区间左右端点的最小字符。若左侧较大,则直接输出右侧最小字符数;若两侧相等,则输出右侧的最小字符数减去左侧的最小字符数;左侧不可能小于右侧。

但是,这种想法有较大漏洞,不能说漏洞,这就是错误的想法,因为这样所记录的最小的字符未必会出现在所求区间内......

作为对自己的警示,把这种错误的东西挂出来侮辱下自己......

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <queue>
 6 #include <stack>
 7 #include <cmath>
 8 #include <map>
 9 using namespace std;
10 int num[100006];
11 char alp[100006];
12 int main()
13 {
14     std::ios::sync_with_stdio(false);
15     int t,len,m,l,r;
16     string s;
17     cin >> t;
18     for(int i = 1; i <= t; i++)
19     {
20         memset(num,0,sizeof(num));
21         cin >> len >> m;
22         cin >> s;
23         cout << "Case #"<< i <<":" << endl;
24         num[0] = 1;
25         alp[0] = s[0];
26         for(int i = 1; i < len; i++)
27         {
28             if(s[i]<alp[i-1])
29             {
30                 alp[i] = s[i];
31                 num[i] = 1;
32             }
33             else if(s[i] == alp[i-1])
34             {
35                 alp[i] = s[i];
36                 num[i] = num[i-1]+1;
37             }
38             else
39             {
40                 alp[i] = alp[i-1];
41                 num[i] = num[i-1];
42             }
43         }
44         while(m--)
45         {
46             cin >> l >> r;
47             l--;
48             r--;
49             if(l==r)
50             {
51                 cout << 1 << endl;
52                 continue;
53             }
54             if(alp[r] < alp[l])
55                 cout << num[r] << endl;
56             else if(alp[r] == alp[l])
57             {
58                 if(alp[l] < s[l] && alp[r] < s[r])
59 //      bug在此: ACBBB...BBCA 查中间,前面白算
60 
61                 if(alp[l]==s[l])
62                     cout << num[r]-num[l]+1 << endl;
63                 else
64                     cout << num[r]-num[l] << endl;
65             }
66         }
67     }
68     return 0;
69 }
View Code

接着又想到可否将最小字符出现的位置记录下来,然后发现完全是在自己哄自己开心......

借助wjy的力量,用二维数组记录位置的似桶排序的做法完成了题目,路还很长......

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 int rc[100100][26];
 5 int main()
 6 {
 7     std::ios::sync_with_stdio(false);
 8     int n,t,q,l,r,j,i;
 9     cin >> t;
10     string s;
11     for(int i=0;i<26;i++)
12     {
13         rc[0][i]=0;
14     }
15     for(int c=1;c<=t;c++)
16     {
17         cout << "Case #" << c << ":" << endl;
18         cin >> n >> q;
19         cin >> s;
20         for(i=0;s[i];i++)
21         {
22             for(j=0;j<=25;j++)
23             {
24                 rc[i+1][j]=rc[i][j];
25             }
26             rc[i+1][s[i]-'A']++;
27         }
28         for(i=0;i<q;i++)
29         {
30             cin >> l >> r;
31             int ans = 0;
32             for(j = 0;ans==0;j++)
33             {
34                 ans = rc[r][j]-rc[l-1][j];
35             }
36             cout << ans << endl;
37         }
38     }
39     return 0;
40 }
View Code
日后若能有更好的想法,再来完善。 希望看到的大神不吝赐教 orz
原文地址:https://www.cnblogs.com/Taskr212/p/9453639.html