POJ 1989 The Cow Lineup
問題
http://poj.org/problem?id=1989
(翻訳)K種類の整数N個からなる整数列が与えられるので、その部分列とならない整数列のうち最短のものの長さを答えろ。
解法
整数列の先頭から、K種類の整数が一通り出るところまで進み、さらにその場所からまたK種類の整数が出そろうところまで進み...を繰り返していき、繰り返した数+1が答え。
適当な証明
上のアルゴリズムをn回繰り返したとする。
入力の整数列を繰り返しによって進んだところで切って、整数列の集合{s1, s2, ... ,sn}が出来る。(全てのsはそれぞれK種類の整数を全て含んでいる)
まず、長さn以下の任意の整数列が{s}に部分列として出現することを示す。
整数列{a1, a2, ... , ai} (i <= n)とおくと、整数列s1は全ての種類の整数を含んでいるので、当然a1もs1の要素である。
同様にajはsjの要素である。
従って、a1∈s1, a2∈s2, ... ,ai∈si となるのでsから適当に要素を選ぶことにより、{s}から長さn以下の任意の整数列を部分列として作ることが出来る。
次に、長さn+1で{s}の部分列でない整数列を作ることが出来ることを示す。
各sの末尾の整数は1回しか現れない(∵そうでないと、アルゴリズムでK種類の整数がちょうど出そろうところまで進むことに矛盾する)
各sから末尾の整数を取り出して出来た整数列を{b1, b2, ... , bn} とする。
この整数列は{s}の部分列として一つだけ存在する。
ここで入力の整数列にアルゴリズムを実行して余った部分(bnの末尾以降)に出現しない整数を{b}の末尾に加えると
{b1, b2, ... , bn, bn+1}となる。
bn+1はbn以降には存在しない整数だから{b1, b2, ... , bn, bn+1}は{s}の部分列としては存在しない。
以上よりn+1が最小の長さであることが示された。
終わり
#include <cstdio> #include <algorithm> using namespace std; int N, K; bool used[10000]; int m; int main(){ scanf("%d %d", &N, &K); int ans = 0; m = 0; for(int i = 0; i < N; i++){ int t; scanf("%d", &t); if(!used[t-1]){ used[t-1] = true; m++; if(m == K){ ans++; m = 0; fill(used, used + K, false); } } } printf("%d\n", ans + 1); return 0; }