ベースハッシュ (自然オーバーフロー)
単一文字列ハッシュを計算する
typedef unsigned long long ull; ull strhash(文字列 &s){ ull H=0、P=131; for(char c:s){ H=H*P+c; } H を返します。 } 文字列の各プレフィックスのハッシュを計算します。 typedef unsigned long long ull; ベクトル<ull> strhash(string &s){ ベクトル<ull> vec; ull H=0、P=131; for(char c:s){ H=H*P+c; vec.push_back(H); } vec を返します。 }
文字列の部分文字列のハッシュ値を計算する
typedef unsigned long long ull; const int N=1e6; ull P=131; ベクトル<ull>PP{1}; void init(){ for(int i=1;i<=N;i++){ PP.push_back(PP.back()*P); } } ベクトル<ull> strhash(string &s){ ベクトル<ull> vec; ull H=0; for(char c:s){ H=H*P+c; vec.push_back(H); } vec を返します。 } ull gethash(vector<ull> &has,int l,int r){ if(l==0) 戻り値 has[r]; has[r]-has[l-1]*PP[r-l+1] を返します。 }
Dmitry には、小文字のラテン文字で構成される文字列 �s があります。
ドミトリーさんは、文字列 �s から連続する 2 文字を削除することにしました。このような操作を行うと、異なる文字列が何個得られるか疑問に思われます。
たとえば、Dmitry には文字列「aaabcc」があります。次の異なる文字列を取得できます: "abcc" (最初の 2 文字または 2 文字目と 3 文字目を削除)、"aacc" (3 文字目と 4 文字目を削除)、"aaac" (4 文字目と 5 文字目を削除)と「aaab」(最後の 2 つを削除)。
入力
入力データの最初の行には、単一の整数 �t (1≤�≤1041≤t≤104)、つまりテスト ケースの数が含まれます。
以下にテスト ケースについて説明します。
各テスト ケースの説明の最初の行には、整数 �n (3≤�≤2⋅1053≤n≤2⋅105) が含まれています。
各テスト ケースの説明の 2 行目には、小文字のラテン文字で構成される長さ �n の文字列 �s が含まれています。
すべてのテスト ケースの �n の合計が 2⋅1052⋅105 を超えないことが保証されます。
出力
テスト ケースごとに 1 つの整数、つまり連続する 2 つの文字を削除することで取得できる個別の文字列の数を出力します。
サンプル1
入力コピー | 出力コピー |
---|---|
7 6 ああabcc 10 ああああああ 6 abcdef 7 彼らは平らではない 6 CCFFFF 4 アバ 5 アババ |
4 1 5 3 3 3 1 |
注記
最初の例はステートメントで説明されています。
3 番目の例では、「cdef」、「adef」、「abef」、「abcf」、「abcd」という文字列が取得されます。
7 番目の例では、削除すると文字列「aba」が生成されます。
#include<iostream>
#include<vector>
#include<algorithm>
名前空間 std を使用します。
typedef unsigned long long ull;
const int N=1e6;
ull P=1007;
ベクトル<ull>PP{1};
void init(){//* 文字部分文字列のハッシュ値を計算
for(int i=1;i<=N;i++){ PP.push_back(PP.back()*P); } }
Vector<ull> strhash(string &s){//文字列の各プレフィックスのハッシュを計算します Vector
<ull> vec;
ull H=0;
for(char c:s){ H=H*P+c; vec。 Push_back(H); } 戻り値 vec; }
ull gethash(vector<ull> &has,int l,int r){ return has[r]-has[l-1]*PP[r-l+1]; }//*
void sol(){ int n;cin>>n; 文字列 s;cin>>s; s="$"+s; ベクトル<ull>は(strhash(s)); ベクトル<ull>vec; for(int i=1;i<=n;i++){ ull pre=has[i-1]; ull suf=gethash(has,i+2,n); vec.push_back(pre*PP[ni-1]+suf); sort(vec.begin(),vec.end());//去重 cout<<unique(vec.begin(),vec.end())-vec.begin()-1<<endl; / /計算異なる数 }
int main(){ init(); int t;cin>>t; while(t--)sol(); 0を返します。}
A - 基本ハッシュ テンプレートの質問
説明
たとえば、�N 個の文字列 (�i 番目の文字列の長さは��Mi、文字列には数字、大文字と小文字が含まれ、大文字と小文字が区別されます) がある場合、�N にはいくつの異なる文字が存在しますか?文字列?文字列。
入力
最初の行には、文字列の数を表す整数 �N が含まれています。
次の �N 行には、それぞれ文字列 (指定された文字列) が含まれます。
出力
出力には、さまざまな文字列の数を表す整数を含む行が含まれます。
サンプル1
入力コピー | 出力コピー |
---|---|
5 ABC ああああ ABC ABC 12345 |
4 |
ヒント
データの 30%30% の場合: ��≤10N≤10、��≈6Mi ≈6、����≤15Mmax≤15。
データの 70%70% の場合: ��≤1000N≤1000、��≈100Mi ≈100、����≤150Mmax≤150。
100%100% データの場合: ��≤10000N≤10000、��≈1000Mi ≈1000、����≤1500Mmax≤1500。
サンプル概要:
この例の最初の文字列 (abc) と 3 番目の文字列 (abc) は同じであるため、指定された文字列のセットは {aaaa,abc,abcc,12345} となり、合計 4 つの異なる文字列が存在します。
#include<iostream>//a
#include<vector>
#include<algorithm>
名前空間 std を使用します。
typedef unsigned long long ull;
ull strhash(string &s){ ull H=0,P=131; for(char c:s){ H=H*P+c; H を返します。}
int main(){ int n;cin>>n; ベクトル<ull>vec; for(int i=1;i<=n;i++){ string s;cin>>s; vec.push_back(strhash(s)); sort (vec.begin(),vec.end()); cout<<unique(vec.begin(),vec.end())-vec.begin()<<endl;
}