[blue《字符串Hash》]同伙
标题:同伙
描述:定义所有个字母序号之和相同的字符串为“同伙”。例如“ABC”和“CC”是一伙的,“ABC”和“AAA”不是一伙的。
输入:第一行为S,第二行为字符串SS。
输出:S中从左向右数第一个子串与SS是同伙,字符串的下标从零开始(的异世界生活(雾)),如果没有同伙,输出-1。
范围:|S|,|SS|<=1000000
来源:blue《字符串HASH》
暴力是个好东西。。枚举一下所有子串,然后叠加一下判一下是否相等就ok。
当然这个算法是O(n3)的。
所以想一想如何去优化。
首先可以用前缀和的方法将上面那个算法降一层n,然而O(n2)的复杂度依然承受不起。。。
然而很容易可以发现,这明明就是一个严格上升序列(貌似即使不是也没关系)!
那么就可以去搞单调队列咯,用尺取法不断挪动顺便判一下!
嗯这就是O(n)了,已经达到理论下界了。(附上不太正确的代码。。)

1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 #include <queue> 7 #include <string> 8 #include <vector> 9 using namespace std; 10 11 deque<int>q; 12 string s,ss; 13 long long h,sum,pos,tot; 14 int main(){ 15 //freopen("test.in","r",stdin); 16 //freopen("test.out","w",stdout); 17 ios::sync_with_stdio(false); 18 cin>>s>>ss; 19 20 #define N 21 22 #ifdef N 23 for(int i=0;i<ss.length();i++)h+=ss[i]-'A'+1; 24 for(int i=0;i<s.length();i++){ 25 while(q.size()&&sum>h){ 26 sum-=q.back(); 27 q.pop_back(); 28 pos++; 29 } 30 if(sum==h)break; 31 q.push_front(s[i]-'A'+1); 32 sum+=s[i]-'A'+1; 33 } 34 cout<<(sum==h?pos:-1)<<endl; 35 #endif 36 37 #ifdef N_3 38 for(int i=0;i<ss.length();i++)h+=ss[i]-'A'+1; 39 for(int i=0;i<s.length();i++){ 40 for(int j=0;j<i;j++){ 41 sum=0; 42 for(int k=j;k<=i;k++){ 43 sum+=s[k]-'A'+1; 44 } 45 if(sum==h){ 46 cout<<j<<endl; 47 return 0; 48 } 49 } 50 } 51 #endif 52 53 #ifdef N_2 54 for(int i=0;i<ss.length();i++)h+=ss[i]-'A'+1; 55 vector<int>v; 56 for(int i=0;i<s.length();i++)v.push_back(s[i]-'A'+1); 57 for(int i=1;i<v.size();i++)v[i]+=v[i-1]; 58 for(int i=0;i<s.length();i++){ 59 for(int j=0;j<i;j++){ 60 if(v[i]-v[max(0,j-1)]==h){ 61 cout<<j<<endl; 62 return 0; 63 } 64 } 65 } 66 #endif 67 //In Fact,N^2 Algorithm Isn't Slow In Random Tests...(Maybe All The Datas Are Easy To Work On) 68 }
(话说为了卡一下暴力和骗分的程序是否应该变成最小满足题意的字串的长度啊。。Orz)