Problem:
Problem D: 僕の友達は小さい

僕には、たくさんの友達がいる。どの友達も、とても小さい。

僕は、よく友達と一緒に出かける。何人かの友達をリュックに入れて、一緒に出かける。

僕は毎朝、その日一緒に出かける友達を決める。空のリュックに、１人ずつ友達を入れていく。

僕は、あまり力が強くない。だから、同時に運べる友達の重さには限界がある。

僕は、重さの限界を超えないように友達を入れていく。どの順番で入れていくかは気分次第。

僕は、入れられる友達がまだ残っている限り、入れるのを止めない。決して止めない。

……ところで、リュックに入った友達の組み合わせは、全部で何パターンあるんだろう？

Input

N W

w1

w2

.

.

.

wn

入力の１行目には、整数N（1 ≤ N ≤ 200）と整数W（1 ≤ W ≤ 10,000）が、この順に空白区切りで書かれている。整数N は友達の数を、整数W は同時に運べる重さの限界をあらわす。重さの合計がW より大きいと運ぶことはできない。

続くN 行には、友達の重さをあらわす整数が書かれている。整数wi（1 ≤ wi ≤ 10,000）が、i 番目の友達の重さをあらわす。

Output

最終的にリュックに入っている友達の組み合わせは何通り考えられるか。その総数を1,000,000,007
で割った余りを出力せよ。なお1,000,000,007 は素数である。

「誰もリュックに入っていない」も１通りとして数えることに注意せよ。

Sample Input 1

4 8
1
2
7
9

Sample Output 1

2

Sample Input 2

4 25
20
15
20
15

Sample Output 2

4

Sample Input 3

6 37
5
9
13
18
26
33

Sample Output 3

6

Solution in C (judge verdict: Time Limit Exceeded)

/*
AizuOnline A2333
My friends are small
*/
#include <stdio.h>
int W,N;
int w[200];
int rs[200];
int us[200];
int  ALLWT;

#define MAXHASH 10000
struct {
  int x;
  int y;
  long long ways;} hash[MAXHASH];
int hashcnt;

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*1371 + y*589) % MAXHASH);
}
int regist_hash(int x,int y,long long ways)
{
  int ptr;

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

  ptr = hashfunc(x,y);
  //printf("REGS0 %d %d:%lld (%d)\n",x,y,ways,ptr);
  for(;ptr;ptr<=MAXHASH)
    {
      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);
  }
}
void init()
{
  int i;

  for(i=0;i<200;i++)
    us[i]=0;

  scanf("%d %d",&N,&W);

  for(i=0;i<N;i++)
    scanf("%d",&(w[i]));
}
int compare(const void *x , const void *y)
{
  return(*(int *)y - *(int *)x);
}
void sort()
{
  qsort(w,N,sizeof(int),compare);
}
runsum()
{
  int i,sum;
  sum = 0;
  for(i=0;i<N;i++)
    rs[i]=999999;

  for(i=N-1;i>=0 && sum <= W;i--)
    {
      sum += w[i];
      rs[i]=sum;
    }
  /*
  for(i=0;i<N;i++)
    printf("%d",rs[i]);
  */
}

// ryukku ni ireteinai tomodati de itiban karui
int lightest()
{
  int * p,ret,i;
  i=N-1;ret=w[N-1];
  while(us[i])
    {   
      ret=w[i];
      i--;
    }
  // printf("LTST=%d \n",ret);
  return(ret);
}

long long calc_combi_ways(int ptr,int total,int depth)
{ 
  long long result;

  // printf("%d %d %d\n",ptr,total,depth);

  result = find_hash(ptr,total);
  if(result != -1)
    return(result);
  if(total < lightest())
    {  // printf("*");
      return(1);}
  else if(ptr > N-1)
    return(0);
  else if(total >= rs[ptr] && total < rs[ptr-1])
    {  // printf("+");
      return(1);  }
  else
    {
      us[ptr]=0;
      result = calc_combi_ways(ptr+1,total,depth+1);
      us[ptr]=1; 
      if(total >= w[ptr])
	result += calc_combi_ways(ptr+1,total-w[ptr],depth+1);
      us[ptr]=0;
      result %= 1000000007LL;
      regist_hash(ptr,total,result);
      return(result);
    }
}

main()
{
  long long ret;
  init();
  init_hash();
  sort();
  runsum();

  ret=calc_combi_ways(0,W,0);
  printf("%lld\n",ret);
  //printf("%d",hashcnt);
return(0);
}