トピックリンクします。https://ac.nowcoder.com/acm/contest/889/E
問題の意味:組み合わせ、2つずつ組み合わせて、n個の個体、M動作は、個人4を識別しようと、2つのプログラムは、セットの二つの数字はありません。
アイデア:最初はC [n]が[4]プログラムの種類は、我々は計算合併が多くのプログラムがいかに数を削減するたびに持っています。本発明の生成物を低減することが選択された番組の数を乗じたセットの2倍合計サイズは、同じで、減算、二つのプログラムの任意の数で計算することができ、残りのセットからの二つのセットにありません利用可能なプログラムの数二組。サイズ互いに素-設定操作や保守、および選択されたプレフィックスを記録し、この場合には、同じプログラム番号の和の二組を考えて設定してください。Cの前処理でのみ得られた組合せの前処理数(N、4)とすることができます。総複雑性はO(mlogn)です。
ACコード:
書式#include <cstdioを> する#include <アルゴリズム> 書式#include <マップ> 使用して 名前空間はstdを、 typedefの長い 長いLL。 const int型 MAXN = 1E5 + 5 。 INTのN、M、ルート[MAXN]、SIZ [MAXN]。 ANS LL、和、C [MAXN] [ 5 ]。 ボイドのinit(){ C [ 1 ] [ 0 ] = 1、C [ 1 ] [ 1 ] = 1 。 C [ 2 ] [ 0 ] = 1、C [ 2 ] [ 1 ] =2、C [ 2 ] [ 2 ] = 1 。 C [ 3 ] [ 0 ] = 1、Cは[ 3 ] [ 1 ] = 3、C [ 3 ] [ 2 ] = 3、C [ 3 ] [ 3 ] = 1 。 以下のために(int型 I = 4 ; I <MAXN; ++ I){ C [i]が[ 0 ] = 1 ; 用(INT J = 1 ; J <= 4 ; ++ j)は C [I] [J] = C [I- 1 ] [J- 1 ] + C [I- 1 ] [J]。 } } int型 GETR(INT K){ 場合(ルート[K] == k)は戻りK。 他の 戻りルート[K] = GETR(ルート[K])。 } int型のmain(){ INIT()。 scanf関数(" %d個の%のD "、&N、&M)。 用(int型 i = 1 ; iが<= N; ++ i)は 、ルート[I] = I、SIZ [I] = 1 。 ANS = C [N] [ 4]; printf(" %LLDする\ n " 、ANS)。 一方、(M-- ){ int型X、Y。 scanf関数(" %dの%のD "、およびX&Y)。 INT XR = GETR(x)は、年= GETR(Y)。 もし(XR == 年){ のprintf(" %LLDする\ n " 、ANS)。 続け; } TX LL = 0、TY = 0 。 もし(SIZ [XR]> = 2)TX = C [SIZ [XR] [ 2 ]。 もし(SIZ [年]> = 2)TY = C [トランプ] [ 2 ]。 合計 - = TX + TY。 ANS = 1LLあなた[X] * [ただし] *(C [N [X] -あなた[トランプ] [ 2 ] - 合計)。 printf(" %LLDする\ n " 、ANS)。 ルート[なお] = XR。 [X] + = [けれども]あなた。 和 + = C [X]] [ 2 ]。 } 戻り 0 。 }