Problem:
1年生 (A First Grader)

問題

JOI君は小学 1 年生である．JOI君は教わったばかりの足し算，引き算がとても好きで，数字が並んでいるのを見ると最後の 2 つの数字の間に「=」を入れ，残りの数字の間に必ず「+」または「-」を入れて等式を作って遊んでいる．例えば「8 3 2 4 8 7 2 4 0 8 8」から，等式「8+3-2-4+8-7-2-4-0+8=8」を作ることができる．

JOI 君は等式を作った後，それが正しい等式になっているかを計算して確かめる．ただし，JOI君はまだ負の数は知らないし，20 を超える数の計算はできない．したがって，正しい等式のうち左辺を左から計算したとき計算の途中で現れる数が全て 0 以上 20 以下の等式だけがJOI君が確かめられる正しい等式である．例えば，「8+3-2-4-8-7+2+4+0+8=8」は 正しい等式だが，途中に現れる 8+3-2-4-8 が負の数なのでJOI君はこの等式が正しいかどうか確かめることができない．

入力として数字の列が与えられたとき，JOI君が作り，確かめることができる正しい等式の個数を求めるプログラムを作成せよ．

入力

入力ファイルは 2 行からなる．1 行目には並んでいる数字の個数を表す整数 N （3 ≤ N ≤ 100）が書かれている．2 行目には 0 以上 9 以下の整数が N 個，空白を区切りとして書かれている．

与えられる入力データの 60% では，JOI君が作り，確かめることができる正しい等式の個数は 231-1 を超えない．また，与えられる入力データの全てにおいて，JOI君が作り，確かめることができる正しい等式の個数は 263-1 を超えない．

出力

JOI君が作り，確かめることができる正しい等式の個数を表す整数を 1 行で出力せよ．

入出力例

入力例 1

11
8 3 2 4 8 7 2 4 0 8 8

出力例 1

10

入力例 1 において，JOI君は 10 個の正しい等式

8+3-2-4+8-7-2-4-0+8=8
8+3-2-4+8-7-2-4+0+8=8
8+3+2+4-8-7+2-4-0+8=8
8+3+2+4-8-7+2-4+0+8=8
8+3-2-4+8-7+2+4-0-8=8
8+3-2-4+8-7+2+4+0-8=8
8-3+2+4-8+7+2+4-0-8=8
8-3+2+4-8+7+2+4+0-8=8
8-3+2-4+8+7+2-4-0-8=8
8-3+2-4+8+7+2-4+0-8=8

を作り，確かめることができるので 10 を出力する．

入力例 2

40
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1

出力例 2

7069052760

入力例 2 において，答えが 32 bit符号付き整数の範囲に収まらないことに注意せよ．

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

Solution in JAVA (judge verdict: Accepted)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
import java.util.StringTokenizer;

class Main{
	public static void main(String[] args) {
		SC sc=new SC(System.in);
		int N=sc.nextInt();
		int[] num=new int[N+1];
		for(int i=0; i<N-1; i++) {
			num[i]=sc.nextInt();
		}
		int ans=sc.nextInt();
		long[][] dp=new long[N+1][21];
		for(int i=0; i<=N; i++) {
			for(int j=0; j<=20; j++) {
				dp[i][j]=0;
			}
		}
		dp[0][0]=1;
		dp[1][num[0]]=1;
		for(int i=1; i<N-1; i++) {
			for(int j=0; j<=20; j++) {
				if(dp[i][j]>0) {		//少なくとも1つは答えがあるとき
					if(j-num[i]>=0) {
						dp[i+1][j-num[i]]+=dp[i][j];	//引き算をするとき
					}
					if(j+num[i]<=20) {
						dp[i+1][j+num[i]]+=dp[i][j];	//引き算をするとき
					}
				}
			}
		}
		pl(dp[N-1][ans]);
	}
	public static void pl(Object o) {
		System.out.println(o);
	}
	public static void pl() {
		System.out.println();
	}
	public static void p(Object o) {
		System.out.print(o);
	}
	static class SC {
		private BufferedReader reader = null;
		private StringTokenizer tokenizer = null;
		public SC(InputStream in) {
			reader = new BufferedReader(new InputStreamReader(in));
		}
		public String next() {
			if (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(reader.readLine());
				} catch (IOException e) {
					throw new UncheckedIOException(e);
				}
			}
			return tokenizer.nextToken();
		}
		public int nextInt() {
			return Integer.parseInt(next());
		}
		public long nextLong() {
			return Long.parseLong(next());
		}
		public double nextDouble() {
			return Double.parseDouble(next());
		}
		public String nextLine() {
			try {
				return reader.readLine();
			} catch (IOException e) {
				throw new UncheckedIOException(e);
			}
		}
	}
}