Problem:
Score : 600 points

Problem Statement

Given are a sequence of N integers A_1, A_2, \ldots, A_N and a positive integer S.

For a pair of integers (L, R) such that 1\leq L \leq R \leq N, let us define f(L, R) as follows:

f(L, R) is the number of sequences of integers (x_1, x_2, \ldots , x_k) such that L \leq x_1 < x_2 < \cdots < x_k \leq R and A_{x_1}+A_{x_2}+\cdots +A_{x_k} = S.

Find the sum of f(L, R) over all pairs of integers (L, R) such that 1\leq L \leq R\leq N. Since this sum can be enormous, print it modulo 998244353.

Constraints

All values in input are integers.

1 \leq N \leq 3000

1 \leq S \leq 3000

1 \leq A_i \leq 3000

Input

Input is given from Standard Input in the following format:

N S
A_1 A_2 ... A_N

Output

Print the sum of f(L, R), modulo 998244353.

Sample Input 1

3 4
2 2 4

Sample Output 1

5

The value of f(L, R) for each pair is as follows, for a total of 5.

f(1,1) = 0

f(1,2) = 1 (for the sequence (1, 2))

f(1,3) = 2 (for (1, 2) and (3))

f(2,2) = 0

f(2,3) = 1 (for (3))

f(3,3) = 1 (for (3))

Sample Input 2

5 8
9 9 9 9 9

Sample Output 2

0

Sample Input 3

10 10
3 1 4 1 5 9 2 6 5 3

Sample Output 3

152

Solution in C# (Mono 4.6.2.0) (judge verdict: Time Limit Exceeded)

using System;
using System.Numerics;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace debug
{
    class main
    {
        static void Main(string[] args)
        {
            //問題クラスを展開
            ProgramF a = new ProgramF();
            a.main();//実行する

        }

    }

    class ProgramA
    {
        public void main()
        {
            //入力
            string[] input = Console.ReadLine().Split(' ');
            int m = int.Parse(input[0]);
            int n = int.Parse(input[1]);

            //偶数同士の組み合わせと奇数同士の組み合わせなので、mC2とnC2を求める
            Console.WriteLine((m - 1) * m / 2 + n * (n - 1) / 2);
        }
    }

    class ProgramB
    {
        public void main()
        {

            //入力
            string s = Console.ReadLine();
            int len = s.Length;

            for (int i = 0; i < (len - 1) / 2; i++)
            {
                //回文かみる
                if (s[i] != s[(len - 1) - i])
                {
                    Console.WriteLine("No");
                    return;
                }

                //前半が回文かみる
                if (s[i] != s[(len - 1) / 2 - i])
                {
                    Console.WriteLine("No");
                    return;
                }

                //後半が回文かみる
                if (s[(len + 3) / 2 + i] != s[len - 1 - i])
                {
                    Console.WriteLine("No");
                    return;
                }

            }

            Console.WriteLine("Yes");

        }
    }

    class ProgramC
    {
        public void main()
        {

            //入力
            double l = double.Parse(Console.ReadLine());

            //a=b=c=l/3のとき最大
            Console.WriteLine((l / 3.0) * (l / 3.0) * (l / 3.0));
        }
    }

    class ProgramD
    {
        public void main()
        {

            //入力
            long n = long.Parse(Console.ReadLine());
            string[] a = Console.ReadLine().Split(' ');
            long[] num = new long[n];
            long sum = 0;

            //それぞれ数がいくつあるか数える
            for (int i = 0; i < n; i++)
            {
                long temp = long.Parse(a[i]);
                num[temp - 1]++;
            }

            //とりあえずすべての数え方を見る
            for (int i = 0; i < n; i++)
            {
                sum += num[i] * (num[i] - 1) / 2;
            }

            //1つずつ禁止されたときに場合を除く（n-1する）。答を出力
            for (int i = 0; i < n; i++)
            {
                long temp = long.Parse(a[i]);
                Console.WriteLine(sum - num[temp - 1] + 1);
            }

        }


    }




    class ProgramE
    {
        public void main()
        {

            //入力
            string[] input = Console.ReadLine().Split(' ');
            int h = int.Parse(input[0]);
            int w = int.Parse(input[1]);
            int k = int.Parse(input[2]);


            //チョコの場所と白の位置把握
            int[,] choco = new int[h, w];
            int count = 0;

            for (int i = 0; i < h; i++)
            {
                string input2 = Console.ReadLine();
                for (int j = 0; j < w; j++)
                {
                    choco[i, j] = input2[j] - '0';
                    if (choco[i, j] == 1)
                        count++;
                }

            }

            //白がk個以下なら切る必要はない
            if (count <= k)
            {
                Console.WriteLine("0");
                return;
            }

            //切る回数
            int ans = 1000000;
            int sum = 0;
            

            //縦の切り口を決める
            for (int i = 0; i < (1 << (h - 1)); i++)
            {
                sum = 0;
                int[] comb = new int[h];
                //まずは横の切り口を記録
                for (int j = 0; j < h - 1; j++)
                    sum += (i >> j) & 1;//切る数を足す

                if (ans <= sum)
                    continue;

                //貪欲法で縦の切る回数を数える
                for (int j = 0; j < w; j++)
                {
                    int part = 0;
                    int flag = 0;
                    //それぞれの部分で分けながらカウントしていく
                    for (int l = 0; l < h; l++)
                    {
                        comb[part] += choco[l, j];

                        if (comb[part] > k)
                        {
                            if (j != 0)
                                flag = 1;
                            else
                                flag = 2;
                        }

                        part += (i >> l) & 1;

                    }

                    //もしk超えてしまったら出す(j !=0の処理）
                    if (flag == 1)
                    {
                       
                        part = 0;
                        //リセット
                        for (int l = 0; l < h; l++)
                            comb[l] = 0;
                        //その列だけ再構成
                        for (int l = 0; l < h; l++)
                        {
                            comb[part] += choco[l, j];
                            part += (i >> l) & 1;
                        }

                        //条件を満たさないなら省く
                        for(int l = 0;l <= part;l++)
                        {
                            if (comb[l] > k)
                                sum += 1000000;
                        }


                        sum++;

                    }
                    
                    //最初の時点で満たさない場合の処理
                    if(flag == 2)
                    {
                        sum = 1000000;
                        break;
                    }
                }

                //最小更新
                if (ans > sum)
                    ans = sum;

            }


            Console.WriteLine(ans);

        }
    }


    class ProgramF
    {
        public void main()
        {

            string[] s = Console.ReadLine().Split(' ');
            int n = int.Parse(s[0]);
            int num = int.Parse(s[1]);
            long MOD = 998244353;

            string[] a = Console.ReadLine().Split(' ');
            long[,,] dp = new long[n + 1,num + 1,3];
            //初項設定
            dp[0, 0, 0] = 1;

            //i番目まで見てその和はSである。そしてそのときL、Rが決まっているかどうかで判定する（t=0は両方決まっていない、t=1はLのみ、t=2は確定）
            for (int i = 0; i < n; i++)
                for (int j = 0; j < num + 1; j++)
                {
                    //和が変わるときの推移を考える
                    long temp = j + long.Parse(a[i]);

                    if (temp <= num)
                    {
                        dp[i + 1, temp, 1] += dp[i, j, 0] + dp[i, j, 1];//ここがスタートのときと継続で足している場合を足す
                        dp[i + 1, temp, 1] %= MOD;
                        dp[i + 1, temp, 2] += dp[i, j, 0] + dp[i, j, 1];
                        dp[i + 1, temp, 2] %= MOD;
                    }

                    //和が変わらないときの推移
                    //決まってない場合は普通に足す。（そもそもその和があることを記録する）
                    dp[i + 1, j, 0] += dp[i, j, 0];
                    dp[i + 1, j, 0] %= MOD;
                    dp[i + 1, j, 1] += dp[i, j, 0] + dp[i, j, 1];//iをLとしてきめる、前のときはすでにiより前でLが決まっているとき
                    dp[i + 1, j, 1] %= MOD;
                    dp[i + 1, j, 2] += dp[i, j, 0] + dp[i, j, 1] + dp[i, j, 2];//両方決まってない場合はiがL,Rのとき、Lが決まっていれば、iをRで考える
                    dp[i + 1, j, 2] %= MOD;
                }

            //答はdp[n,num]で出てくる
            Console.WriteLine(dp[n, num, 2]);

        }
    }
}