Problem:
シルクロード (Silk Road)

問題

現在カザフスタンがある地域には，古くは「シルクロード」と呼ばれる交易路があった．

シルクロード上には N + 1 個の都市があり，西から順に都市 0, 都市 1, ... , 都市 N と番号がつけられている．都市 i - 1 と都市 i の間の距離 (1 ≤ i ≤ N) は Di である．

貿易商である JOI 君は，都市 0 から出発して，都市を順番に経由し，都市 N まで絹を運ぶことになった．都市 0 から都市 N まで M 日以内に移動しなければならない．JOI 君は，それぞれの日の行動として，以下の 2 つのうちいずれか 1 つを選ぶ．

移動： 現在の都市から 1 つ東の都市へ 1 日かけて移動する．現在都市 i - 1 (1 ≤ i ≤ N) にいる場合は，都市 i に移動する．

待機： 移動を行わず，現在いる都市で 1 日待機する．

移動は大変であり，移動するたびに疲労度が溜まっていく．シルクロードでは日毎に天候の変動があり，天候が悪い日ほど移動には苦労を要する．

JOI 君が絹を運ぶのに使える M 日間のうち j 日目 (1 ≤ j ≤ M) の天候の悪さは Cj であることが分かっている．都市 i - 1 から都市 i (1 ≤ i ≤ N) に j 日目 (1 ≤ j ≤ M) に移動する場合，疲労度が Di × Cj だけ溜まってしまう．移動を行わず待機している日は疲労度は溜まらない．

JOI 君は，それぞれの日の行動をうまく選ぶことで，できるだけ疲労度を溜めずに移動したい．JOI 君が M 日以内に都市 N に移動するときの，移動を開始してから終了するまでに溜まる疲労度の合計の最小値を求めよ．

入力

入力は 1 + N + M 行からなる．

1 行目には，2 つの整数 N, M (1 ≤ N ≤ M ≤ 1000) が空白を区切りとして書かれている．これは，シルクロードが N + 1 個の都市からなり，JOI 君が絹を都市 0 から都市 N まで M 日以内に運ばなければならないことを表す．

続く N 行のうちの i 行目 (1 ≤ i ≤ N) には，整数 Di (1 ≤ Di ≤ 1000) が書かれている．これは，都市 i - 1 と都市 i の間の距離が Di であることを表す．

続く M 行のうちの j 行目 (1 ≤ j ≤ M) には，整数 Cj (1 ≤ Cj ≤ 1000) が書かれている．これは，j 日目の天候の悪さが Cj であることを表す．

出力

JOI 君が M 日以内に都市 N に移動するときの，移動を開始してから終了するまでに溜まる疲労度の合計の最小値を 1 行で出力せよ．

入出力例

入力例 1

3 5
10
25
15
50
30
15
40
30

出力例 1

1125

入力例 2

2 6
99
20
490
612
515
131
931
1000

出力例 2

31589

入出力例 1 において，溜まる疲労度の合計を最小にするように JOI 君が移動するには次のようにする．

1 日目は待機する．

2 日目に都市 0 から都市 1 へ移動する．このとき溜まる疲労度は 10 × 30 = 300 である．

3 日目に都市 1 から都市 2 へ移動する．このとき溜まる疲労度は 25 × 15 = 375 である．

4 日目は待機する．

5 日目に都市 2 から都市 3 へ移動する．このとき溜まる疲労度は 15 × 30 = 450 である．

JOI 君がこのように移動した場合に溜まる疲労度の合計は 300 + 375 + 450 = 1125 である．これが最小値である．

問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in JAVA (judge verdict: Time Limit Exceeded)

import java.util.Scanner;
public class Main {
	static int g_n;
	static int g_m;
	static int cnt = 0;
	static int mcnt = 0;

	public static int loop(int i,int pointer,int sum[][],int sum_copy[][]){
		int min = 999999;
		int point1 = pointer;
		int point2 = pointer+1;
		cnt++;
		if(point2 >= g_n){
			//System.out.println(cnt+":]");
			return 0;
		}
		for(int l = i+1;l < g_m-(g_n-pointer-2);l++){
			pointer = point1;
			for(int o = l+1;o < g_m-(g_n-pointer-2);o++){
				pointer = point2;
				for(int p= o;p < g_m-(g_n-pointer-1);p++){//10
					//System.out.print(p+"+");
					loop(p-1,pointer,sum,sum_copy);
					//mcnt++;
					if(p == o){
						min = sum[pointer][p];
					}
					min = Math.min(min,sum[pointer][p]);
/*					if(min > sum[pointer][p]){
						min = sum[pointer][p];
					}
					*/
					if(p == g_m-(g_n-pointer-1)-1){							
						if((sum[pointer-1][l] != sum_copy[pointer-1][l] && sum[pointer-1][l] > sum_copy[pointer-1][l]+min) ||(sum[pointer-1][l] == sum_copy[pointer-1][l])){
							sum[pointer-1][l] += min; 
						}	
					}
					
				}
			}
		}
		return 0;
	}
	//????????????
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();
		int min = 99999999;
		g_n = n;
		g_m = m;
		int pointer = 0;
		//n = 5
		//m = 10??¨??????
		int dis[] = new int[n];
		int wea[] = new int[m];
		int sum[][] = new int[n][m];
		int sum_copy[][] = new int[n][m];
		int wea_copy[] = new int[m-n];
		for(int i = 0;i < n;i++){
			dis[i] = sc.nextInt();
		}
		for(int i = 0;i < m;i++){
			wea[i] = sc.nextInt();
		}
		for(int i = 0;i < n;i++){
			for(int j = 0;j < m;j++){
				if(i > j || j-i > m-n){
					sum[i][j] = -1;
					sum_copy[i][j] = -1;
				}else{
					sum[i][j] = dis[i]*wea[j];
					sum_copy[i][j] = sum[i][j];

				}
			}
		}
		//System.out.print(m);
				
		/*
		for(int i = 0;i <m-n ;i++){//5
			pointer=0;
			for(int j = i+1;j <m-(n-pointer-2);j++ ){//10-(4-0)
			pointer=1;
				for(int k = j+1;k < m-(n-pointer-2);k++){//10-(4-1)
			pointer=2;
					for(int l= k+1;l < m-(n-pointer-2);l++){//8
			pointer=3;
						for(int o= l+1;o < m-(n-pointer-2);o++){//9
							//System.out.print("o="+o+":"+n+":"+pointer+":"+(m-(n-pointer-1))+":");
			pointer=4;
							for(int p= o;p < m;p++){//10
								if(p == o){
									min = sum[pointer][p];
								}
								if(min > sum[pointer][p]){
									min = sum[pointer][p];
								}
								if(p == m-1){							
									if((sum[pointer-1][l] != sum_copy[pointer-1][l] && sum[pointer-1][l] > sum_copy[pointer-1][l]+min) ||(sum[pointer-1][l] == sum_copy[pointer-1][l])){
										System.out.println("k"+k+"j"+j+"j"+j+"pointer"+pointer);
										sum[pointer-1][l] += min; 
									}	
								}
							}
						}

					}	
				}
			}
		}
		*/
		loop(-1,0,sum,sum_copy);
		//loop4(5);
		min = sum[0][0];
		for(int i = 0;i < m-n;i++){
			if(min > sum[0][i]){
				min = sum[0][i];
			}
		}
/*
		for(int i = 0;i < n;i++){
			for(int j = 0;j < m;j++){
				//System.out.print(sum[i][j]+":");	
			}
			//System.out.println();
		}	

*/		System.out.println(min);

	}
}