[Luogu P1381]は言葉の問題の解決策を暗唱します

単語の朗読

タイトル説明

霊夢n個の言葉はあなたが戻って持つようにしたいが、彼女は1品の期間でこれらの単語を覚えたいです。

記事は、彼女は彼女が(唯一の一つとして数え繰り返し)バックたかった単語を含むほとんどが、記事の連続期間を見つけたい、m個の単語で構成されています。そして、状況の限り数量ワード朗読ではなく、記事できるだけ短く選出された段落にするために、彼女は言葉できるだけ多くを学ぶために最短時間を使用することができます。

入力形式

最初の行番号N、

次のn行の各列バックワードを表すために、もはや10以下です。

数m、続い

ストリング10は、もはやm行より次いでていない各記事における単語を表します。

出力フォーマット

総出力ファイル2行。2番目の行に含まれる記事の最初の行為にバックアップしたい単語の数は、バック物品における最短の連続的なセグメントに単語を表現するために最大の長さを含んでいます。

サンプル入力と出力

入力#1
3
ホット
ミルク
5
ホット
ミルク
ホット
出力#1
3
3

説明/ヒント

[データ範囲]

nのデータの30%<= 50、M <= 500。

nのデータの60%<= 300、M <= 5000。

データの100%にN <= 1000、M <= 100000。

 

トピックの意味:

言葉の二組を考えます。

1単語1のセット、コレクション内の数字2が表示されますがどのようなものです。

倍のQの最大数、最短連続サブセット2の組の最初の発生を満たすために求めの場合2。

 

分析:

文字が対処するのは非常に簡単ではありませんので、我々はデジタルに変換するためにハッシュ文字列を使用しているので、我々は文字列よりも、この方が便利に対処します。

もちろん、あなたが維持するためにマップを使用することができます。

最初の質問に関しては比較的簡単です。

(:、はい0:1ない)がなかった場合にV1 [] 0/1 BOOLアレイとセット1のワードを記録します。

そして、2が決定される設定。

 

2番目の質問の難しさ。

nが、それは、線形の基本的なニーズが考えられる、比較的大きいです。

私は単調なキューのアプローチを提供します。

まず、いくつかの変数を宣言します。

1 LST [ハッシュ値(S)]は現在の文字列、文字列sの最初の出現位置に処理を表します。 

現在の文字列、寄与番号列への処理を示す2. NUMカウンタは、文字列の数がセット1(回カウントと同じ)で表示されています。

3. V2 [ハッシュ値(S)] sがない場合、文字列を考慮する必要がなく、セット2及びセット内の1現れるを表します。

 

NUM = ANS1は、すべての答えを更新するときには、明確な得ることができます。

 

次の最も重要なことは、単調なキューは内部に置く何ですか?

私たちは、[i]は、各貢献列Bに入ります。

その位置のモノトーン。

文字列が同じの下に表示された場合、それはいじっすることができます。

だから、私たちは(NUM == ANS1)の回答を数えるとき

私たちは、私+ 1位マイナスいくつかの区間の長さのための条件であるキューの最初の要素の現在の位置を使用しています。

 

最後の文特に約0。

書式#include <iostreamの> 
の#include <cstdioを>  
する#include <CStringの>
 使用して 名前空間はstd;
CONSTの INT N = 1E6、P = 1E7 + 9、INF = 1E9。
INTの N、M、ANS1、ANS2 = INF。
INT [N]、B [N]。
ブール V1 [P + 1 ]、V2 [P + 1 ]、VIS [P + 1 ]。
INT LST [P]、Q [N]。
チャー S [ 20 ]。
インラインINTハッシュ(チャー *のS){//ハッシュ関数
     INT LEN =のSTRLEN(S);
     ロング ロング RES = 0 ;
     のためのint型私は= 0 ; IはLEN <Iは++ ){
        RES * = 31 ;
        RES + = S [I] - [ A ' 
        問題%= P;
    }
    リターンのres;
}
int型のmain()
{
    int型I、J。
    scanf関数(" %のD "、&N)
    (i = 1 ; iが<= N; iは++ ){
        scanf関数(" %sの" 、S);
        [I] = ハッシュ(S)。
        V1 [A [I] = 1 ; // V1 [] 1つのレコードれるコレクションで発生
    }
    scanf関数(" %のD "、&M)。
    (i = 1 ; iが<= M; iは++ ){
        scanf関数(" %sの" 、S);    
        B [i]は = ハッシュ(S)。
        もし{(V1 [i]と[B])
             であれば(! {[[I] B] V2)
                V2 [B [I] = 1 
                ANS1 ++ ;
            }
        }
    }
    INT NUM = 0、ヘッド= 1、尾= 0 ;
     のための(I = 1 ; I <= M、Iは++ ){
         IF(LST [B [I]] == 0 && V2 [B [I])NUM ++ ;
         IF (V2 [i]の[B] {//) !V2は[]寄与しない場合
            LST [B [I] = I。
            Q [ ++尾] = I;
        }
        一方、(ヘッド<=尾&& Q [ヘッド] <LST [B [Q [ヘッド]]])ヘッド++ もし(NUM == ANS1)ANS2 =分(ANS2、IQ [ヘッド] + 1 ); //更新答案
    }
    もし(ANS1)のprintf(" %d個の\ n%D " 、ANS1、ANS2)。
    のprintf(" 0 \ N0 " );
}

 

おすすめ

転載: www.cnblogs.com/quitter/p/11774334.html