Problem:
Problem F: １０歳の動的計画

ある日の夕方。いつものようにあなたが居間でテレビを見ていると、小学５年生の妹から相談を持ち
かけられた。話を聞いてみると、今日学校で出された算数の問題が難しくて理解できなかったので、
あなたに解き方を教えてほしいのだという。

妹を悩ませている問題は、「道が碁盤目状に通っている街において、家(0, 0) から学校(N, M) まで最短距離で進む方法は何通りあるか？」というものだった。もちろん、あなたにとっては赤子の手をひねるよりも簡単な問題である。すぐに上のような図を書いて「家(0, 0) から順番に足し算していけば解けるよ」と教えてあげた。

ところが、それを聞いてもまだ、妹はなにやら下を向いて考えこんでいる。あなたは、自分の説明の
仕方が悪かったのだろうかと思ったが、どうやらそうではないらしい。

たっぷり３分ほど悩んでいただろうか。妹は、おもむろに顔を上げると、あなたに向かってこう言っ
た。

「でも、わたしだったら、きっと学校に行く途中でK 回くらい寄り道しちゃうだろうな……。ねぇお
兄ちゃん、そうすると答えは何通りになるの？」

さあ大変だ。兄の威厳を保つため、なんとしてもこの問題に答えねば。

この問題を定式化すると、次のようになる。

点(0, 0) から点(N, M) まで、碁盤目状の道を通って進む方法は何通りあるか答えよ。

基本的には右か上に１マス進むが、途中で、ちょうどK 回だけ寄り道をする。

「寄り道をする」とは、左か下に１マス進むことである。

K 回の寄り道をすませていない場合、いったん点(N, M) に着いた後でも歩き続ける。途中で点(0, 0) に戻ってくる場合もある。

家はこの街の隅に建っているので、X 座標またはY 座標が負になるような点に入ることはできない。

しかし、X 座標がN より大きな点、または、Y 座標がM より大きな点には入ることができる。

Input

N M K

入力の１行目には、整数N（1 ≤ N ≤ 100,000）と整数M（1 ≤ M ≤ 100,000）と整数K（0 ≤ K ≤ 10,000）が、この順に空白区切りで書かれている。整数N は学校のX 座標を、整数M は学校のY座標を、整数K は寄り道の回数をあらわす。

Output

点(0, 0) から点(N, M) まで、K 回の寄り道をして進む方法。その総数を1,000,000,007 で割った余りを出力せよ。なお1,000,000,007 は素数である。

Sample Input 1

6 4 0

Sample Output 1

210

Sample Input 2

3 3 1

Sample Output 2

448

Sample Input 3

124 218 367

Sample Output 3

817857665

Solution in C (judge verdict: Wrong Answer)

/*
AizuOnline A2335
10-Year-Old Dynamic Programming
*/
#include <stdio.h>
#define MAXHASH 1600000
int W,H,K;

struct {
  short x;
  short y;
  long long ways;} hash[MAXHASH];
int hashcnt;
struct {
  short x;
  short y;
  short z;
  long long ways;} hash2[MAXHASH];
int hash2cnt;

int init_hash()
{
  int i;
  for(i=0;i<MAXHASH;i++)
    {
      hash[i].x = 0;
      hash[i].y = 0;
      hash[i].ways = -1LL;
    }
  hashcnt=0;
}

int hashfunc (int x,int y)
{
  return((x*31371 + y*2689) % MAXHASH);
}

int regist_hash(int x,int y,long long ways)
{
  int ptr,ptr1;

  if(hashcnt >= MAXHASH/2)
    return(-1);

  ptr = hashfunc(x,y);
  ptr1 = ptr;
  // printf("REGS0 %d %d:%lld (%d)\n",x,y,ways,ptr);
  for(;ptr<MAXHASH;ptr++)
    {
      if(hash[ptr].x == x && hash[ptr].y == y)
	return(-2);
      if(hash[ptr].ways == -1LL)
	goto REG;
    }
  for(ptr=0;ptr<ptr1;ptr++)
    {
      if(hash[ptr].x == x && hash[ptr].y == y)
	return(-2);
      if(hash[ptr].ways == -1LL)
	goto REG;
    }
 REG:
  // printf("REGS1 %d %d:%lld (%d)\n",x,y,ways,ptr);
  hash[ptr].x = x;
  hash[ptr].y = y;
  hash[ptr].ways = ways;
  hashcnt++;
  return(ptr);
}

long long find_hash(int x,int y)
{
  int ptr;

  ptr = hashfunc(x,y);
 
  while(1)
    {
      if(hash[ptr].x == x && hash[ptr].y == y)
	{
	  // printf("FIND %d %d:%lld\n",x,y,hash[ptr].ways);
	  return(hash[ptr].ways);      
	}
      if(hash[ptr].ways == -1)
	return(-1LL);
      ptr++;
      if(ptr >= MAXHASH)
	ptr=0;
    }
}
/**HASH 2**/

int init_hash2()
{
  int i;
  for(i=0;i<MAXHASH;i++)
    {
      hash2[i].x = 0;
      hash2[i].y = 0;
      hash2[i].z = 0;
      hash2[i].ways = -1LL;
    }
  hashcnt=0;
}

int hashfunc2 (int x,int y,int z)
{
  return((x*31371 + y*2689 + z*16711) % MAXHASH);
}

int regist_hash2(int x,int y,int z,long long ways)
{
  int ptr,ptr1;

  if(hash2cnt >= MAXHASH/2)
    return(-1);

  ptr = hashfunc2(x,y,z);
  ptr1 = ptr;
  // printf("REGS0 %d %d:%lld (%d)\n",x,y,ways,ptr);
  for(;ptr<MAXHASH;ptr++)
    {
      if(hash2[ptr].x == x && hash2[ptr].y == y && hash2[ptr].z == z)
	return(-2);
      if(hash2[ptr].ways == -1LL)
	goto REG;
    }
  for(ptr=0;ptr<ptr1;ptr++)
    {
      if(hash2[ptr].x == x && hash2[ptr].y == y && hash2[ptr].z == z)
	return(-2);
      if(hash2[ptr].ways == -1LL)
	goto REG;
    }
 REG:
  // printf("REGS1 %d %d:%lld (%d)\n",x,y,ways,ptr);
  hash2[ptr].x = x;
  hash2[ptr].y = y;
  hash2[ptr].z = z;
  hash2[ptr].ways = ways;
  hash2cnt++;
  return(ptr);
}

long long find_hash2(int x,int y,int z)
{
  int ptr;

  ptr = hashfunc2(x,y,z);
 
  while(1)
    {
      if(hash2[ptr].x == x && hash2[ptr].y == y && hash2[ptr].z == z)
	{
	  // printf("FIND %d %d:%lld\n",x,y,hash[ptr].ways);
	  return(hash2[ptr].ways);      
	}
      if(hash2[ptr].ways == -1)
	return(-1LL);
      ptr++;
      if(ptr >= MAXHASH)
	ptr=0;
    }
}

long long combi(int n,int r)
{
  long long ret;
  if((ret=find_hash(n,r)) > 0)
    return(ret);
  if(r==0 || r==n)
    return(1);
  ret=(combi(n-1,r)+combi(n-1,r-1)) % 1000000007;
  regist_hash(n,r,ret);
  return(ret);
}

int f(int nu,int nd,int x)
{
  int ret;
  //printf("%d %d %d\n", nu, nd, x);
  if((ret=find_hash2(nu,nd,x)) > 0)
    return(ret);

  if (x < 0) 
    return(0);
  if (0 == nu)
    if(x >= nd)
      return(1);
    else
      return(0);
  else if (1 == nd)
    if(0 == x)
      return(nu);
    else
      return(1 + nu);
  else
    {
      ret = (f(nu-1, nd ,x+1) + f(nu,nd-1,x-1)) % 1000000007;
      regist_hash2(nu,nd,x,ret);
      return(ret);
    }
}

int f1(int N,int K1 )
{
  if ( K1 == 0)
    return(1);
  else
    return( f( N- K1, K1, 0));
}


long long f2335 (int W,int H, int K)
{ long long sum,product;
  int x;

  sum = 0LL;
  for(x=0;x<=K;x++)
    {
    product = (combi(W+H+2*K,W+x*2)*f1(W+2*x,x)) % 1000000007LL;
    sum += (product*f1(H+(K-x)*2,K-x)) % 1000000007LL;
    sum %= 1000000007LL;
    // printf("%lld\n",sum);
    }
  return(sum);
		}

main()
{
  init_hash();
  init_hash2();
  scanf("%d %d %d",&W,&H,&K);
  printf("%lld\n",f2335(W,H,K));
  printf("%d %d\n",hashcnt,hash2cnt);

return(0);
}