SRM321 div2

問題文の読み間違い。k-double stringsの個数を求める.0-strings ~ k-stringsまでの個数を求めるのではない.
問いの文はi-double stringsはk-double strings(i <= k)でもあるんだよ、といっているだけ.
easy

  int howMuch(vector <string> str, int k) {
    string s;
    for(int i = 0, len = str.size(); i < len ;i++) {
      s += str[i];
    }
    int len = s.length();
    int ans = 0;
    for(int i = 2; i <= len; i += 2) {
      for(int pos = 0; pos <= len-i; pos++) {
	string first = s.substr(pos, i/2);
	string second = s.substr(pos+i/2, i/2);
	int cnt = 0;
	for(int j = 0; j <= i/2; j++) {
	  if(first[j] != second[j]) {
	    cnt++;
	  }
	}
	if(cnt <= k) ans++;
      }
    }
    return ans;
  }

medium

//easyよりも簡単
#define INF (1<<30)
class Chocolate {
	public:
	int minSplitNumber(int width, int height, int nTiles) {
    int ans = INF;
    if(width < height) swap(width, height);
    for(int i = 1; i*i<= nTiles; i++) {
      int tmp = 2;
      if(nTiles%i == 0) {
        int a = i; //small
        int b = nTiles/i; //large
        if(height < a || width < b) continue;
        if(height == a || height == b) tmp--;
        if(width == b || width == a) tmp--;
        
        ans = min(ans, tmp);
      }
    }
    return (ans == INF) ? -1 : ans;       
	}
	

difficult
純粋なDPではおそらくとけない。とけるが、通った道も記憶していなければならないので、dp[len+1][len][len]みたいになる。
これでは、あまりメモ化する意味はない。(メモ化は、何回も値を参照するときに有効であることを意識する)
たとえば、dp[len+1][len](dp[cnt][length])とおくとする。
なぜなら、i個目の文字がprint_outされたとして、i+1個目の文字に行くとき、次に訪問していない文字が特定できないから。
たとえば、2個目に3番目の数に到達したとする。次に進みたいとき、一度出力した文字の場所をたどってしまう。

aaaa
0000
0123
???? <--DPにするならここをどう漸化式で表現するかだが、
???? <--通ったか通っていないか分からないので、表現できない。


この問題は再帰関数で表現すればいい。

aaabbaababb
TTTFTTTFTFF:通ったか
    .      ;現在位置(現在7文字出力完了)
   *   *   :次に行き当たる文字。右or左に最初に突き当たる条件をみたす文字。
//次に行き当たる文字を総当たり式に調べていくのはNG.
次の文字のときおそらく間に合わなくなる。
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaとか。
#define INF (1<<30)
class LexStringWriter {
  private:
    string str;
    string sorted;
    int go(int cnt, int pos);
    bool used[51];
	public:
	int minMoves(string s) {
    str = s;
    sorted = s;
    sort(sorted.begin(), sorted.end());
    memset(used, false, sizeof used);
    return go(0, 0)+s.length();
  }
};

//ここはもうちょっと簡略化できるかも。
int LexStringWriter::go(int cnt, int pos) {
  if(cnt == str.length() ) return 0;
  int ans;
  if(str[pos] == sorted[cnt] && used[pos] == false ) {
    used[pos] = true;
    ans = min(ans, go(cnt+1, pos) );
    used[pos] = false;
  } else {
    for(int i = pos+1; i < str.length(); i++) {
      if(str[i] == sorted[cnt] && used[i] == false ) {
        used[i] = true;
        ans = min(ans, go(cnt+1, i)+i-pos );
        used[i] = false;
      }
    }
    for(int i = pos-1; i >= 0; i--) {
      if(str[i] == sorted[cnt] && used[i] == false) {
        used[i] = true;
        ans = min(ans, go(cnt+1, i)+pos-i );
        used[i] = false;
      }
    }
  }
  return ans;
}