ロシアコヌドカップ2012予遞ラりンドのタスクの詳现分析準決勝





先週の土曜日、6月16日、ロシアコヌドカップ2012の予遞ラりンドは終了したした。予遞ラりンドのタスクは予遞よりも耇雑です-それが準決勝の理由です。 私はすでに、以前のオンラむンツアヌで参加者に提䟛されたものに぀いお話し、゜リュヌションオプション Q1 、 Q2 、 Q3 を詳现に分析したした。



600名が予遞に招埅されたした。 434人が少なくずも1぀の問題を解決できたした。 すべおのタスクは2人で解決されたした。 最高の50人が決勝に進出したした。 ツアヌのわずか3時間で、3190の゜リュヌションがテストシステムに送信されたした。



それでは、タスク自䜓に移りたしょう。 私はそれらを説明しようずしたので、スポヌツプログラミングの最初の䞀歩を螏み出す人たちそしお実際にはプログラミング党般でも決定が明確になるようにした。



終了

問題の本質は、2皮類の順列を任意の順序で適甚するこずにより、倀のリスト内の指定された䜍眮から指定された䜍眮に芁玠を移動できるかどうかを刀断するこずでした。 問題の状態により、最初の2぀の芁玠を亀換するいわゆる順列ず、倀のルヌルセットa1、a2、...、aNによっお定矩される耇雑な順列を適甚するこずができたした。各倀は、移動可胜な䜍眮のシリアル番号を決定したす。この䜍眮からの番号。 たずえば、順列芏則の最埌の2぀1,4,3,2は、最埌の䜍眮から2番目に再配眮でき、それから最埌に再配眮できるこずを意味したす。 実際には、最埌に、このリストN個の倀ずフォヌム䜍眮1、䜍眮2を含む入力デヌタに「はい/いいえ」ずいう圢匏の回答を䞎える必芁がありたす-「芁玠を䜍眮1から䜍眮2に移動できたすか」。



このタスクはコンテストで最も簡単で、411人がそれに察凊したした。最初のテストは、ラりンドの開始から3分31秒でDmitry Zhukovによっお提案されたした。



明らかに、すべおの順列は最終的に䞀連のルヌプになりたす。 䞊蚘のサむクル3の䟋では、4-> 2-> 4-> 2 ... 1-> 1-> 1 ... 3-> 3-> 3 ...぀たり、「pを適甚する」ずいう操䜜だけがあった堎合、 2぀の芁玠aiずbiに぀いおは、これらの芁玠が順列pの1サむクルにある堎合に限り、答えは「はい」になりたす。



「順列」zを適甚するずどうなるか考えおみたしょう。 最初に1番目ず2番目の芁玠が異なるサむクルにある堎合、「順列」を䜿甚するず、これら2぀のサむクルの1぀から別の芁玠に芁玠を再配眮する機䌚が䞎えられたす。



これで、䞀般的な゜リュヌションを定匏化できたす。





サむクルぞの分割は次のずおりです。



//    col,   −1. vector<int> col(n, −1); //    ,    ,       for (int i = 0; i < n; i++) { if (col[i] != −1) continue; //     int x = i; do { col[x] = i; //    x = a[x]; } while (col[x] == −1); }
      
      







最初の2぀のサむクルを1぀に結合したす。



 for (int i = 0; i < n; i++) if (col[i] == 0) col[i] = 1;
      
      







その結果、colの配列が埗られ、そのi番目の芁玠はi番目の䜍眮を含むサむクルを瀺したす。



 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; //  ,          . cout << ((col[a — 1] == col[b — 1])? «Yes» : «No») << «\n»; }
      
      







Cor冠匏

問題の状況に応じお、2぀の銖郜ず特定の数の郜垂があり、道路で接続されおいるため、どの道路からでも唯䞀の道路がありたす。 しかし、それらは、各道路に瀺されおいる特定の数の車を通過した埌、旅行に適さないほどの品質です。 2぀の郜垂の間に垯域幅が無制限の別のおそらく重耇する道路を远加するこずが決定されたした。 この新しい道路を考慮しお、2぀の銖郜間を走行できる車の最倧数を芋぀ける必芁がありたす。



問題の詳现な声明は、ロシアコヌドカップの公匏りェブサむトのラりンドペヌゞにありたす 。



このタスクは、「最埌から」2番目に難しいこずが刀明したした。313人が解決したした。 最初の正しい決定は、1250にDmitry Zhukovによっお送信されたした。



問題には、重みのある無向ツリヌがありたす。 ぀たり、ルヌプず耇数の゚ッゞがなく、その゚ッゞ「道路」が「重み」で曞かれおいるグラフ-道路のスルヌプット。



2぀のピヌクが匷調衚瀺されたす-「資本」-sおよびt。 sからtぞのフロヌが最倧になるように、sたたはtに圱響しない゚ッゞを远加する必芁がありたす。



頂点aから頂点bに゚ッゞを远加したしょう。 sずtの間に最倧2぀の単玔なパスが存圚するこずを蚌明したしょうパスは、その゚ッゞが繰り返されない堎合、単玔ず呌ばれたす。 私たちは反察から蚌明したす。 3぀の方法を芋぀けたずしたす。



次の2぀の堎合を考えたす。







その結果、゚ッゞabを远加するず、2぀以䞋の単玔なパスが衚瀺され、そのうちの1぀だけが゚ッゞabを持ち、もう1぀は明らかにツリヌの゚ッゞに沿っお通過するため、頂点郜垂間の唯䞀のパスであるこずがわかりたした。



゚ッゞabを通る2番目のパスを考えたす。 䞀端では、この゚ッゞは頂点sぞのパスに接続され、他端では頂点tぞのパスに接続されたす。 ここで、abず<s; a>のゞャンクションをsに近いノヌドに移動しおも、スルヌプットは䜎䞋したせん。 同様にtぞの道に぀いお議論し、問題の制玄を思い出しお、資本ノヌドs、t、および゚ッゞabを最も効果的な圢で通過する新しいパスは、sからの゚ッゞ、sからabおよびtからの゚ッゞ。



その結果、答えは2぀のパスで構成され、1぀ぱッゞabを远加する前に存圚し、もう1぀はsからの゚ッゞ、゚ッゞab、tの゚ッゞであるこずがわかりたす。



゜リュヌションを取埗したす。

  1. ツリヌの゚ッゞに沿っおsからtぞのパスを芋぀け、
  2. それに沿っお車の最倧数をスキップし、それに応じお、道に沿っおすべおのrib骚のスルヌプットを枛らしたす。 この堎合、最倧数のマシンがパスに含たれる゚ッゞの最小スルヌプットに察応するため、パスは間違いなく厩壊したす。
  3. sずtからより倚くの道路たたは1぀の道路が存圚する可胜性がありたす。 最倧スルヌプットを持぀ものを遞択したす。
  4. それらを゚ッゞabで接続しお、車の数を蚈算したす。これは、銖郜を離れる2぀のrib骚のスルヌプットからの最小倀です。




゜シオフォベ

問題の条件は、最小限の削枛でここにもたらすこずです。



「すべおの人が垞に矀衆の䞭にいるこずを喜んでいるわけではありたせん。 倚くの人が孀独を愛し、その代䟡を払っおも構わないず思っおいたす。 OJSC「Joyful Railways」がチケット販売りェブサむトで「Sociophobe」ず呌ばれる新しいサヌビスを導入したのはそのためです。 このサヌビスは、各乗客が可胜な限り少ない数の隣人のいる区画に乗るこずができるようにするために必芁です。 その本質は次のずおりです。



チケットは、コンパヌトメントの䞀郚がすでに満たされおいる台車で販売されたす。 ある時点で別の乗客がこの車のチケットを賌入するず、最も空いおいる区画、぀たり他のすべおの人よりも倚くの人がいない区画で座垭を販売されたす。 そのようなコンパヌトメントが耇数ある堎合、最も小さい番号のコンパヌトメントが遞択されたす。 ただし、いずれかのコンパヌトメントの乗客がチケットを発行するず、このコンパヌトメントず最も満員のコンパヌトメントの人数の差が少なくずも2になった堎合、他のコンパヌトメントの前にチケットを賌入した乗客は、最も満員のコンパヌトメントから空いおいるコンパヌトメントに転送され、番号が最も小さい乗客がいたす。 最もいっぱいの区画が耇数ある堎合、チケットが配られた区画に最も近い区画が遞択されたす。 そしお、それらが耇数ある堎合、最も小さい番号のコンパヌトメントが遞択されたす。



乗客がチケットを賌入しお配垃した方法に応じお、コンパヌトメント内の乗客の最終的な分垃を衚瀺する必芁がありたす。 乗客がチケットを賌入するたびに、車内に少なくずも1぀の無料座垭があるこずが保蚌されおいたす。




問題の列車は本圓に巚倧なようです。なぜなら、チケットの販売ずチケットの返华の数は最倧200,000、クヌペの数は最倧50,000であるからです。



合蚈で167人がこの問題を解決したした。最初の人はPavel Kuniavsky23:19でした。



この問題の解決策の1぀は次のずおりです。 次のデヌタ構造を準備したす。



 // ,     . Pas[i] = , -1  «  ». vector<int> pas(200000+1, -1); //   –    . Cars[i]     vector< set<int> > cars(50000 + 1);
      
      







たた、2぀のセットをサポヌトしたすたずえば、C ++では、このためにJavaのTreeSetでsetを䜿甚できたす0ず1。 れロでは、乗客数が最も少ないコンパヌトメント番号を栌玍し、1぀では-最も倚いコンパヌトメント番号を栌玍したす。



 set<int> zero; set<int> one;
      
      







最初は、すべおのコンパヌトメントが空であるため、それらを塗り぀ぶしの候補リストに入れたす-れロ。



 for (int i = 1; i <= n; i++) zero.insert(i);
      
      







異なる区画の乗客数の差が1を超えるこずはないため、他の人は必芁ありたせん。



チケット販売操䜜「+」。 問題の状況に応じお、最も人数が少ない車を遞択する必芁がありたす。 これを行うには、蚭定されたれロの最小芁玠を取埗したす。 pasずcarsの情報をそれぞれ曎新したす。 次に、芋぀かった芁玠を0から削陀しお1に远加したす。これは、この車にはすべおの車が1぀に䞊んでいるのず同じ数の人がいるからです。 れロが空になった堎合、すべおのクヌペは同じ人数であるため、1ず0を亀換する必芁がありたす。



 int car = *zero.upper_bound(0); //    pas[++id] = car; //      cars[car].insert(id); //       zero.erase(car); //        one.insert(car); // 
     if (zero.empty()) //   ,      
 { zero = one; //        zero.erase(-n); zero.erase(2 * n); one.clear(); //     one.insert(-n); one.insert(2 * n); }
      
      







チケット配信操䜜 "-"。 pas配列を䜿甚しお、乗客がどのコンパヌトメントに座っおいたかを調べたす。 察応するコンパヌトメントから乗客を取り陀きたす。



 int car = pas[x]; cars[car].erase(x); pas[x] = −1;
      
      







車のクヌペに属しおいたものをご芧ください。 以䞋のオプションがありたす。







 set<int>::iterator ll = (one.upper_bound(car)); ll--; //  ,    set<int>::iterator rr = (one.upper_bound(car)); //  ,    if (abs(*ll - car) > abs(*rr - car)) //        ll = rr; int l = *ll; one.erase(l); zero.insert(l); //   one  zero int p = *cars[l].upper_bound(0); cars[l].erase(p); cars[car].insert(p); //      pas[p] = car;
      
      







タスクぞの回答を衚瀺するには、cars配列を䜿甚したす。 i番目のコンパヌトメントの乗客に関する情報を衚瀺するには、セットされおいる車のサむズ[i]を衚瀺するだけで十分です。



 cout << cars[i].size() << ((cars[i].size() == 0) ? "\n" : " ");
      
      







そしお、倚くの車に属するすべおの乗客[i]。



 set<int>::iterator en = cars[i].end(); en--; for (set<int>::iterator it = cars[i].begin(); it != cars[i].end(); it++) cout << *it << ((it == en) ? "\n" : " ");
      
      







硬貚

問題の状況に応じお、ある魔術垫のリンセりィッドはコむンを混同し、䟋えばダブロンで支払う代わりに、スタヌリングをカりントしたす同時に、圌は本物のスタヌリングで支払いたせん。 コむンのペアがいく぀あるかを蚈算する必芁がありたす。そのため、最初のコむンを2番目に取っお、蚈算したずおり、SではなくTドルを正確に支払うこずができたす。



説明のために䟋を瀺したす。 流通しおいる1、2、3ドルの硬貚があり、Riswindが9ではなく10ドルを支払った堎合、1の硬貚に察しお2の硬貚を受け入れ、たずえば2の硬貚4枚ず2の硬貚1枚を支払うこずでこれを行うこずができたす圌は額面「1」のためにそれを取った。



圌はたた、2の宗掟のコむンに察しお3の宗掟のコむンを受け入れ、1の宗掟で7コむン、3の宗掟で1コむンを支払い、それを2の宗掟でコむンずしお取りたした。



実際に額面で支払われる金額1 名目倀2で実際に支払われる金額 額面金額3で実際に支払われる金額 支払総額
- ほんずに

4コむン

8ドル、4×2



1コむン

2ドル、2×1

Riswindの芋解では-



1ドル1×1

- ほんずに

5コむン



10ドル、4×2 + 2×1



Riswindの芋解では-



9ドル4×2 + 1×1
ほんずに

7コむン

7ドル、7×1
- ほんずに

1コむン

3ドル、3×1

Riswindの芋解では-

2ドル2×1
ほんずに

8コむン

10ドル、4×2 + 1×1

Riswindの芋解では-

9ドル4×2 + 2×1




Rincewindがsのコむンtを取ったず仮定したす。 最埌の䟋では、コむン3tが2sです。 これは、コむンsこの䟋では$ 7を䜿甚せずに特定の金額V䟋では$ 10を獲埗し、その埌、別のkコむン番号t䟋では1コむン 3、それが2だず思っお。



぀たり、さたざたなオプションが2぀のケヌスグルヌプに収たりたす。





最初の条件はO1で怜蚌できたす。 に泚意しおください



k =S-T/as-at;

V = S-k



埗られた数倀が敎数、V≥0、k> 0であるこずを怜蚌するこずは残っおいたす。



2番目の条件を確認するために、動的蚈画法を䜿甚したす。 D [i] [j]ずする-最初のi個のコむンを䜿甚しお合蚈jを取埗するこずは可胜ですか ベヌスD [0] [0] = true。 遷移D [i] [j] = D [i-1] [j]たたはD [i] [j-ai]。 実装には、サむズSの1぀の配列で十分ですが、このアルゎリズムの実行時間はOS・nです。 動的プログラミングを䜿甚したアプロヌチの詳现な説明に぀いおは、 最埌のラりンドからのタスクの分析、 および䟋ず図を含む優れた資料を参照しおください。



説明した方法を䜿甚しお、Rinncewindがコむンsを䜿甚せずにこの合蚈を収集できたかどうかを、1からSたでの合蚈Vに぀いお蚈算したす。 その埌、Rincewindが取ったコむンを敎理したす。 これで、O1の䞡方の条件の怜蚌が実行されたす。 結果ずしお埗られる解の挞近挙動はOS・n2です。



「コむン」のタスクは、1706にPeter Mitrichevによっお最初に解決されたした。 合蚈で234の正しい決定があり、このタスクは耇雑さの点で最埌から3番目になりたした。



行解析

この問題は、特定のテキストからの語圙単語の怜玢アルゎリズム-発芋された単語がこのテキストから削陀されるたびに、いわゆる欲匵りアルゎリズムに぀いお説明したす。 堎合によっおは、このアプロヌチが誀った結果に぀ながるずいう䟋が瀺されおいたす。 たずえば、workingrassの堎合、workingは削陀され、䞀郚のrassがありたすが、正しい解決策は、work / in / grasの3぀の単語に分割し、それぞれを蟞曞に入れるこずです。 貪欲なアルゎリズムが指定された蟞曞で正しく機胜するかどうかを確認する必芁がありたす。正しくない堎合は、蟞曞からの単語分割が存圚するが、説明されたアルゎリズムでは芋぀からない文字列の䟋を瀺したす。 そのような䟋が耇数ある堎合は、最も短いもの、぀たり長さが他の郚分より長くないものを芋぀ける必芁がありたす。 耇数ある堎合は、いずれかを印刷する必芁がありたす。



たず、問題の解決に぀ながる重芁なアむデアを怜蚎したす。 文字列t-最短長の必芁な反䟋ず、蟞曞w 1 、w 2 、...、w kからの単語ぞの分割があるずしたす。 この行を調べる際に砎壊しようずしおいる貪欲なパヌサヌを、文字列wを最初に「食い蟌たせ」たす。



次のステヌトメントを蚌明したしょう。文字列の長さwが文字列の長さw 1 、w 2 、...、w k-1の合蚈よりも倧きくない堎合、文字列tより短い反䟋がありたす。



たず、文字列tの長さをこの合蚈に等しくしたす。 次に、文字列wが最初に「噛み付いお」から、文字列tが蟞曞に含たれる最も長い文字列プレフィックスであるため、文字列tで貪欲なパヌサヌが正しく動䜜するこずは明らかです。



この堎合、文字列の長さwを文字列の長さw 1 、w 2 、...、w k-1の合蚈よりも小さくしたす。 次に、w jが接頭蟞w j1ず接尟蟞w j2に分割され、w j1が文字列wの接尟蟞長さがれロの堎合もあるであるような番号jが存圚したす。 文字列w j2を考えたす。 圌女のために蟞曞から単語ぞの正しいパヌティションがある堎合、反䟋ずしお、行j j2 、w j + 1 、w j + 2 、...、w kの連結を残すだけで十分です。これはより短い反䟋になりたす。 文字列w j2に察しお 、蟞曞からの単語分割が原則ずしお存圚しない堎合、短い反䟋は文字列w 1 、w 2 、...、w jの連結です。







だから、今、私たちは望たしい反䟋がどのように芋えるか想像するこずができたす。







その構築に有効なアルゎリズムを開発したす。 蟞曞の各行に぀いお、どの接尟蟞ず接頭蟞が蟞曞からの単語に分類されおいるかを確認したすこのデヌタの蚈算方法に぀いおは埌で説明したす。 ディクショナリのすべおの行を゜ヌトしお、それらが最初に「噛み付いた」w行であるかどうかを確認したす。 正しいパヌティションから最埌から2番目の行は、パヌティションがある行プレフィックスwが終わる同じ堎所でのみ終了できるこずは明らかです。 このようなすべおのプレフィックスに぀いお説明したす。 これで、反䟋の正しい分割の最埌の行を理解するだけです。 たず、これらは、チェック察象の文字列のただカバヌされおいない接尟蟞wの長さよりも長い行である必芁がありたす。 第二に、文字列wのカバヌされおいない接尟蟞は、察応する長さのパヌティションの最埌の堎所の候補文字列の接頭蟞ず正確に䞀臎する必芁がありたす。 そしお最埌に、文字列wでカバヌされおいない候補文字列の接尟蟞には、蟞曞からの単語ぞの正しい区切りがないはずです。



ここで重芁なポむントを1぀挙げるのが適切です。 候補文字列のカバヌされおいない接尟蟞が蟞曞から単語に分割されたずしおも、珟圚チェックしおいるこずは反䟋になりたす。 ただし、サフィックス自䜓が反䟋になり、チェックするのは探しおいる最短の反䟋ではなく、興味がありたせん。







問題を解決するこのアプロヌチでは、もう1぀質問する必芁がありたす。 そしお、チェックしおいる行wの代わりに、最初の行がwが接頭蟞である別の行に「噛み付いた」堎合、どうなりたすか この堎合、貪欲なパヌサヌは予枬できない動䜜をし、䜕らかのパヌティションを芋぀ける可胜性がありたす。 ただし、この運呜を回避するには、行の長さが増加しない順でw文字列でないかどうかを確認し、既に確認した行を芚えおおく必芁がありたす。 次に、そのような問題が発生する可胜性のある各行は、問題が発生する時間たでにチェックされ、この行は単玔に無芖できたす。



問題を解決するための䞀般的なアルゎリズムが甚意されたので、接頭蟞ず接尟蟞の壊れやすさをチェックする問題を解決し、必芁な行の必芁な郚分文字列をすばやく比范しお同等にする方法も孊習したす。 2番目の問題は、それ自䜓が別の蚘事たたは講矩のトピックであるハッシュアルゎリズムの助けを借りお非垞に簡単に解決されたす。 最初のタスクは、動的プログラミングを䜿甚しお解決されたす。 文字列tのすべおのプレフィックスに぀いお、その長さが厳密にlより短い堎合、蟞曞からの行ぞの分割があるかどうかを確認したす。 長さlのプレフィックスのパヌティションがあるかどうかを確認するには、蟞曞からすべおの行を敎理し、2぀のステヌトメントが真になるように存圚を確認するだけで十分です。







, O(sumL × n), sumL — , n — , , . , .



« » ( ) « », , – 115:47.



, , . , / , . , , , . , , , — Impossible.



, , x , x — . : (0, 0) (x, y) y, ( ), ( ) (). .







, , , . , , .



, . , , «» , . , . . , - . . , .



, . , . , . , , , , - . , . , , . x, . , , .



, , . O(n2 log n) , O(n) O(n) O(n) . O(n log n) , O(n) .



, .







そしお







.







– 23 , – 100:18. , , – , 2 . , .








50 . 10 Swissotel, . , , , .



アリ゚フ・ラりフ



Mail.Ruグルヌプ




All Articles