Codeforces 1178F DP

質問の意味:紙の白い部分を持って、あなたはこのノートに染色を与える必要があります。開始染色染色色1から、一枚の紙を染色し、各選択期間と、このセクションは、同じ色でなければなりません。今、私たちは、あなたは染色、染色プログラムの後に注意を与え、そこにあるどのように多く尋ねましたか?

F1:アイデア:1次元の順序の初めのアイデアは、DPに他の二つの次元のために、その後、染色範囲を染色している​​が、最終的に、見つけることができないため、不確実性の裏に染色のすべてのインパクト前に、染料のみで最初のいくつかの色は今染色した切片を決定することができない、だけでなく、メモリの問題の解決策を参照してください。比較的賢いの問題を解決するためのDP公式デザイン。私たちは、DP染めため、間隔で我々の焦点を気にしないでください。初めてその色の最小値でなければなりませんカラーラベルを染めるようになったために私たちは、範囲を見つけることができます。現在の間隔が[L、R]、色cがPである最小基準の位置であり、c区間[a、b]はこの区間では、間隔は、4つの部分に分割されることによって着色されていると仮定:[L、 - 1]、[P - 1]、[P + 1、B]、[B + 1、R]、再帰的な四つの部分を解決し、それに対する回答を掛けます。見つけるのは簡単でB列挙は、Bの解答と回答の列挙の列挙が、それに取り、得られた、独立しています。

コード:

#include <ビット/ STDC ++ H> 
に#define INF 0x3f3f3f3f 
の#define PII対<整数、整数> 
の#defineは、二重DB 
の#defineが長い長いLL 
名前空間stdを使用。
CONST INT MAXN = 510。
constのLL MOD = 998244353; 
[MAXN] [MAXN] DP LL。
N INT、M。
PII C [MAXN]。
<整数> S、S1を設定します。
<整数>設定::イテレータit。
INTをL [MAXN]、R [MAXN]。
int型のCNT [MAXN]。
int型MI [MAXN] [MAXN]。
LL DFS(int型のL、R INT){ 
	IF(R <= 1)リターン1。
	IF(!DP [L] [R] = -1)戻りDP [L] [R]。
	INT P = MI [L] [R]。
	LL SUM1 = 0、SUM2 = 0。
	{ - (; iがpは<I ++は1 iがLに= INT)のため
		SUM1 + =(DFS(L、I)* DFS(I + 1、P - 1))%MOD。
	}
	SUM1の%= MOD。
	(INT J = P; J <= R; J ++){ため
		SUM2 + =(DFS(P + 1、J)* DFS(J + 1、R))%MOD。
	} 
	SUM2%= MOD。
	DP [L] [R] =(SUM1 * SUM2)%MOD。
	DP [L] [R]を返します。
} 
int型のmain(){ 
	scanf関数( "%D%dの"、&N、&M)。
	memsetの(DP、-1、はsizeof(DP))。
	以下のために(INT i = 1; iが<= N; iが++){ 
		scanf関数( "%のD"、&C [i]の1次回)。
		C [i]は.second = I。
		L [I] = 1、R [I] = N。
	} 
	s.insert(0)。
	s.insert(N + 1)。
	ソート(C + 1、C + 1個の+ N)。
	以下のために(INT i = 1; iが<= N; iは++){ 
		L [I] =(*( - s.lower_bound(C [i]の.second)))。
		R [I] =(* s.lower_bound(C [i]の.second))。
		L [I] ++、R [I] - 。
		(; J <= C [i]の.second; J ++ [I] INT J = L)のために
			(; kは<= R [I] ++ kは整数kは= Cを[I] .second)用
				MI [J] [K] = C [i]の.second。
		s.insert(C [i]の.second)。
	} 
	COUT << DFS(1、N)<< ENDL。
}

F2:今範囲は1E6、直接ではなくDPの範囲であることに注意。しかし、カラー上の隣接する位置の紙の同じ数存在する場合、それは位置に縮小することができる観察、いずれかのこれらの位置をカバーしていない全体、またはすべてのカバレッジ、及び同じ位置の貢献として。法律上のポイント還元がすべて1000以上、1,000以上のポイントではありません後にプログラムを見つけるのは簡単である場合にはゼロに直接出力することができます。収縮ポイントとF1の後のようになってますが、注意が必要いくつかの小さな細部きました。プログラムを決定するための最初の必要性は、2つの色が途中で同じ位置を有する場合、その基準色よりも小さい見やすい、正当であり、プログラムは有効ではありません。その上でこの直接判定暴力。DP計算方式は、四つの部分F1を除いて、間隔の最小値の複数の基準位置が存在し得る場合次に、これらの位置の間の間隔は、取るべきです。最後に、我々は、この例のように、F1として直接間隔を列挙することはできません。

8 10
8 4 3 5 7 5 2 6 2 1

見つけるのは簡単、私たちは左の点間隔をカバーするカバレッジゾーン2を列挙したときにカバーされている場合、ここ2 5 2間(右端5を含む)にすることはできません、5この状況はそうではありません。それについてのような治療のポインタ。

コード:

#include <ビット/ STDC ++ H> 
に#define INF 0x3f3f3f3f 
の#define PII対<整数、整数> 
の#defineは、二重DB 
の#defineが長い長いLL 
名前空間stdを使用。
const int型MAXN = 1010; 
constのLL MOD = 998244353; 
[MAXN] [MAXN] DP LL。
N INT、M。
int型のC [1000010]。
INTをL [MAXN]、R [MAXN]。
int型CNT [MAXN]、最後に[MAXN]、次に[MAXN]。
int型MI [MAXN] [MAXN]。
ベクター<PII> [MAXN]再。
LL DFS(int型のL、R INT){ 
	IF(R <= 1)リターン1。
	IF(!DP [L] [R] = -1)戻りDP [L] [R]。
	INT LP = L [M [L] [R]、RP = R [M [L] [R]]。
	LLのSUM1 = 0、SUM2 = 0、SUM3 = 1。
	INT今= MI [L] [R]。
	以下のために(INT i = 0; iは<再[今] .size(); iは++){
		SUM3 =(SUM3 * DFS(再[今] [i]が1次回、再[今] [I] .second))%MOD。
	} 
	ための式(I = 1の値int - 1; I <LP; I =次に[I]){ 
		SUM1 + =(DFS(L、I)* DFS(I + 1、LP - 1))%MOD。
	} 
	SUM1%= MOD。
	用(INT J = RPあり、j <= R J =次に[J]){ 
		SUM2 + =(DFS(RP + 1、J)* DFS(J + 1、R))%MOD。
	} 
	SUM2%= MOD。
	DP [L] [R] =(((SUM1 * SUM2)%のMOD)* SUM3)%MOD。
	DP [L] [R]を返します。
} 
int型のmain(){ 
	scanf関数( "%D%dの"、&N、&M)。
	以下のために(INT I = 1; I <= M; iは++){ 
		scanf関数( "%のD"、&C [I])。
	} 
	INT TOT = 0。
	TOT = 1。
	{(; I <= M I ++はiは2 = INT)のために
		{ - ([1 I] C [I] == c)の場合 
			続けます。
		}他{ 
			C [++ TOT = Cを[I]。
		} 
	} 
	もし(TOT> 1000){ 
		のprintf( "0 \ n"); 
		0を返します。
	} 
	のmemset(DP、-1、はsizeof(DP))。
	memsetの(最後に、-1、はsizeof(最後)); 
	以下のために(INT I = 1; I <= TOT; iは++){ 
		MI [i]は[I] = Cを[I]。
		{(; J <= TOT J ++のint J = I + 1)のための
			MI [I] [J] =分(C [J]、MI [I]、[J - 1])。
		} 
		Lの[I] = TOT + 1。
		R [I] = 0; 
	} 
	ブールフラグ= 0。
	(I = 1 int型; I <= TOT; iが++)は{ 
		L [C [I] =分(L、I [i]はCを]); 
		R [C [I] = MAX(R [C [I]、I)。
		IF(最終[Cの[I] = -1!){ 
			IF(MI [最後[C [I] + 1] [I - 1] <C [I]){ 
				フラグ= 1。
				ブレーク;
			} 
			。一back(make_pair(最終[C [I] + 1、I - 1))[I] C]再。
		} 
		最後[Cの[i]は] = I。
	} 
	ため(INT i = 0; I <= TOT; iは++){ 
		次に[I] = R [C [I + 1]。
	} 
	次に[TOT] TOT + 1 =。
	IF(フラグ){ 
		のprintf( "0 \ n"); 
		0を返します。
	} 
	COUT << DFS(1、TOT)<< ENDL。
	0を返します。
}

  

おすすめ

転載: www.cnblogs.com/pkgunboat/p/11222356.html