[BZOJ 3097] Hash Killer I, bzoj3097
3097: Hash Killer ITime Limit: 5 Sec Memory Limit: 128 MBSec Special Judge
Submit: 382 Solved: 145
[Submit] [Status] Description
The weather was good this day. The hzhwcmhf God gave VFleaKing a question:
Here is a string S with a length of N. How many different substrings with a length of L are required.
Substrings are defined as consecutive segments such as S [l], S [l + 1], and... S [r.
The two strings are considered to be different when and only when the characters at a certain position are different.
VFleaKing I think this is not a Hash bare question! Therefore, hash + sorting is written.
The hzhwcmhf gods naturally know that this is the number of <L + 1 in the height of the suffix array, that is, the number of nodes containing L in the length range represented by the suffix automatic machine, the number of nodes with the suffix tree depth of L.
However, the hzhwcmhf God looked at VFleaKing and said it was very sweaty. So I tried to get rid of him.
VFleaKing uses the lexicographic hash, and its code is roughly as follows:
U64 val = 0;
For (int I = 0; I <l; I ++)
Val = val * base + s [I]-'A ';
U64 is an unsigned int64 in the range of [0, 2 ^ 64 ). VFleaKing naturally overflows val.
Base is a constant. VFleaKing determines its value based on the mood.
VFleaKing also obtains the base ^ l, that is, the l power of the base, so that the hash value of all the substrings with the length of L can be conveniently obtained.
Then, VFleaKing sorts the hash values, de-Duplicates them, and calculates the number of different hash values. The result is the number of hash values.
The C ++ code of the algorithm is as follows:
Typedef unsigned long u64;
Const int MaxN = 100000;
Inline int hash_handle (const char * s, const int & n, const int & l, const int & base)
{
U64 hash_pow_l = 1;
For (int I = 1; I <= l; I ++)
Hash_pow_l * = base;
Int li_n = 0;
Static u64 li [MaxN];
U64 val = 0;
For (int I = 0; I <l; I ++)
Val = val * base + s [I]-'A ';
Li [li_n ++] = val;
For (int I = l; I <n; I ++)
{
Val = val * base + s [I]-'A ';
Val-= (s [I-l]-'A') * hash_pow_l;
Li [li_n ++] = val;
}
Sort (li, li + li_n );
Li_n = unique (li, li + li_n)-li;
Return li_n;
}
Hzhwcmhf certainly knows how to get stuck! But he wants to test you.
Input
No input.
Output
You need to output a set of data so that the VFleaKing code is WA. We will use Special Judge to check whether your results are correct.
The output file contains two rows.
The numbers n and l separated by spaces in the first line.
The second line is a string with a length of n. It can only contain 'A '~ 'Z '.
1 <= n <= 10 ^ 5, 1 <= l <= n,
If it does not conform to the preceding format, it will be WA.
Do not have extra characters, which may lead to your WA.
No Sample Input
Sample Output8 4
Buaabuaa
(Of course, this output will be WA)
HINT
Orz Pole & fotile96 & sillycross
Source
VFleaKing & hzhwcmhf
It is a magical construction question.
First, understand two points:
1. The key to card hash is to construct two different strings with the same hash value.
2. u64 is equivalent to modulo 2 ^ 64.
If the base is an even number, then ......... aaa (> 64 a) and ba ....... aa (the number of strings a is the number of strings a before-1). The two strings have the same length and hash value. Obviously, the strings are different, so they will be dropped.
If the base number is an odd number, it will be troublesome.
Let's take a look at vfk's practices:
If the base is an odd number, only letters a and B are considered. A \ B indicates that a can divide B. (Orz specific mathematics) set the mathematical function not (S) to convert 'A' at each position in string S to 'B ', converts 'B' into a string. For example, not ("ababaa") = "bababb" strA. strB indicates String concatenation. For example, "". "Haha" = "Wahaha" | str | indicates the length of the str string. Set the string sequence {orzstr [I]}, orzstr [1] = "a", orzstr [I] = orzstr [I-1]. not (orzstr [I-1]) | orzstr [I] | = | orzstr [I-1] | * 2. Obviously, this is an equal-to-ratio series. The result is: | orzstr [I] | = | orzstr [1] |. 2 ^ (I-1) = 2 ^ (I-1) set hash (str) to the hash value of str. Then: hash (orzstr [I]) = hash (orzstr [I-1]) * base ^ | not (orzstr [I-1]) | + hash (not (orzstr [I-1]) = hash (orzstr [I-1]) * base ^ (2 ^ (I-2 )) + hash (not (orzstr [I-1]) hash (not (orzstr [I]) = hash (not (orzstr [I-1]) * base ^ (2 ^ (I-2) + hash (orzstr [I-1]) subtraction: hash (orzstr [I]) -hash (not (orzstr [I]) = (hash (orzstr [I-1]) * base ^ (2 ^ (I-2 )) + hash (not (orzstr [I-1])-(hash (not (orzstr [I- 1]) * base ^ (2 ^ (I-2) + hash (orzstr [I-1]) = (hash (orzstr [I-1]) -hash (not (orzstr [I-1]) * (base ^ (2 ^ (I-2)-1) This lets us find that, hash (orzstr [I])-hash (not (orzstr [I]) seems to be a magic thing. In fact, our goal is to find two strings, strB, so that hash (strA) % 2 ^ 64 = hash (strB) % 2 ^ 64 is equivalent to 2 ^ 64 \ hash (strA)-hash (strB) set the series {f [I]}, f [I] = hash (orzstr [I]) -hash (not (orzstr [I]): f [I] = f [I-1] * (base ^ (2 ^ (I-2 )) -1) It's still a bit uncomfortable ...... Let's set another series {g [I]}, g [I] = base ^ (2 ^ (I-1)-1, so we can write: f [I] = f [I-1] * g [I-1] Then f [I] = f [1] * g [1] * g [2] *. .. * g [I-1] then discover a magic thing? If base is an odd number, any positive integer of base must be an odd number. Therefore, for any I, g [I] must be an even number, so the question of 2 ^ (I-1) \ f [I] is over ...... No ...... In this case, we need to make 2 ^ 64 \ f [I], at least let I = 65 ...... Then we found that | orzstr [65] | is an astronomical number. We found that the analysis just now is too boring ...... I> 1: g [I] = base ^ (2 ^ (I-1)-1 = (base ^ (2 ^ (I-2)-1) * (base ^ (2 ^ (I-2) + 1) = g [I-1] * an even number while g [1] is obviously an even number ...... So 4 \ g [2], 8 \ g [3]... that is to say 2 ^ I \ g [I] So f [I] Actually has :( 2 ^ 1) * (2 ^ 2) * (2 ^ 3 )*... * (2 ^ (I-1) \ f [I] 2 ^ (I * (I-1)/2) \ f [I] When I get 12, there are 66 2! This is the method when the card base is an odd number. Orzstr [12] and not (orzstr [12]) are what you want.
In the reading, the base has both an odd number and an even number. Simply add 64 a strings after the odd number.
#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>#include <cstdlib>#include <string>using namespace std;char s[10000];int main(){cout<<(1<<11)+65<<" "<<(1<<10)<<endl;int now=1;s[1]='a';for (int i=1;i<=11;i++){for (int j=1;j<=now;j++)s[now+j]=s[j]=='a'?'b':'a';now<<=1;}for (int i=1;i<=now;i++)printf("%c",s[i]);for (int i=1;i<=65;i++)printf("a");printf("\n");return 0;}
Perception:
1. The key to this constructor is to construct two strings to be the same as 2 ^ 64, so that the difference between the two strings or the two strings is more than 64 2.
2. Other questions about hash killer: vfk blog