#![allow(dead_code)]
use crate::modulo::*;
use crate::scanner::Scanner;
modint!(998244353);
fn main() {
    let mut scan = Scanner::new();
    let n = scan.read::<usize>();
    let s = scan.read::<usize>();
    let a = scan.readn::<usize>(n);
    let mut dp = vecs ! ( Z :: new ( 0 ) ; s + 1 );
    dp[0] = Z::new(1);
    for i in 0..n {
        let mut tmp = vec![Z::new(0); s + 1];
        std::mem::swap(&mut tmp, &mut dp);
        for j in 0..=s {
            dp[j] += tmp[j] * 2.into();
            assign!(dp[j + a[i]] += tmp[j]);
        }
    }
    println!("{}", dp[s]);
}
mod tiny_num_traits {
    pub trait ZeroOne {
        fn zero() -> Self;
        fn one() -> Self;
    }
    macro_rules! impl_zero_one {
        ( $ tpe : ident ) => {
            impl ZeroOne for $tpe {
                fn zero() -> Self {
                    0
                }
                fn one() -> Self {
                    1
                }
            }
        };
    }
    impl_zero_one!(i64);
    impl_zero_one!(i32);
    impl_zero_one!(usize);
}
mod scanner {
    use std::io::{stdin, BufReader, Bytes, Read, Stdin};
    use std::str::FromStr;
    pub struct Scanner {
        buf: Bytes<BufReader<Stdin>>,
    }
    impl Scanner {
        pub fn new() -> Scanner {
            Scanner {
                buf: BufReader::new(stdin()).bytes(),
            }
        }
        pub fn read_next<T: FromStr>(&mut self) -> Option<T> {
            let token = self
                .buf
                .by_ref()
                .map(|c| c.unwrap() as char)
                .skip_while(|c| c.is_whitespace())
                .take_while(|c| !c.is_whitespace())
                .collect::<String>();
            token.parse::<T>().ok()
        }
        pub fn read<T: FromStr>(&mut self) -> T {
            self.read_next().unwrap()
        }
        pub fn readn<T: FromStr>(&mut self, n: usize) -> Vec<T> {
            (0..n).map(|_| self.read::<T>()).collect()
        }
        pub fn chars(&mut self) -> Vec<char> {
            self.read::<String>().chars().collect()
        }
    }
}
mod macros {
    #[macro_export]
    macro_rules ! for_ { ( $ init : stmt ; $ cond : expr ; $ incr : expr , $ body : block ) => { $ init while $ cond { $ body $ incr ; } } ; }
    #[macro_export]
    macro_rules ! vecs { ( $ init : expr ; $ ( $ dim : expr ) ;* ) => { vecs ! ( $ ( $ dim ) ;* => $ init ) } ; ( $ head : expr ; $ ( $ tail : expr ) ;* => $ init : expr ) => { vec ! [ vecs ! ( $ ( $ tail ) ;* => $ init ) ; $ head ] } ; ( $ head : expr => $ init : expr ) => { vec ! [ $ init ; $ head ] } ; }
    #[macro_export]
    macro_rules! chmax {
        ( $ x : expr , $ y : expr ) => {
            if $x < $y {
                $x = $y;
                true
            } else {
                false
            }
        };
    }
    #[macro_export]
    macro_rules! chmin {
        ( $ x : expr , $ y : expr ) => {
            if $x > $y {
                $x = $y;
                true
            } else {
                false
            }
        };
    }
    #[macro_export]
    macro_rules ! assign { ( $ arr : ident $ ( [ $ a : expr ] ) + = $ right : expr ) => { unsafe { assign ! ( $ arr , $ ( [ $ a ] ) + , = , $ right , default ) ; } } ; ( $ arr : ident $ ( [ $ a : expr ] ) + += $ right : expr ) => { unsafe { assign ! ( $ arr , $ ( [ $ a ] ) + , += , $ right , default ) ; } } ; ( $ arr : ident $ ( [ $ a : expr ] ) + -= $ right : expr ) => { unsafe { assign ! ( $ arr , $ ( [ $ a ] ) + , -= , $ right , default ) ; } } ; ( $ arr : ident $ ( [ $ a : expr ] ) + |= $ right : expr ) => { unsafe { assign ! ( $ arr , $ ( [ $ a ] ) + , |= , $ right , default ) ; } } ; ( $ arr : ident $ ( [ $ a : expr ] ) + &= $ right : expr ) => { unsafe { assign ! ( $ arr , $ ( [ $ a ] ) + , &= , $ right , default ) ; } } ; ( $ arr : ident $ ( [ $ a : expr ] ) + ^= $ right : expr ) => { unsafe { assign ! ( $ arr , $ ( [ $ a ] ) + , ^= , $ right , default ) ; } } ; ( $ arr : ident $ ( [ $ a : expr ] ) + min $ right : expr ) => { unsafe { assign ! ( $ arr , $ ( [ $ a ] ) + , ^= , $ right , min ) ; } } ; ( $ arr : ident $ ( [ $ a : expr ] ) + max $ right : expr ) => { unsafe { assign ! ( $ arr , $ ( [ $ a ] ) + , ^= , $ right , max ) ; } } ; ( $ arr : expr , [ $ head : expr ] , $ op : tt , $ right : expr , default ) => { let head = $ head ; if 0 <= head as i64 && ( head as i64 ) < $ arr . len ( ) as i64 { let tmp = $ right ; *$ arr . get_unchecked_mut ( head as usize ) $ op tmp ; } } ; ( $ arr : expr , [ $ head : expr ] , $ op : tt , $ right : expr , min ) => { let head = $ head ; if 0 <= head as i64 && ( head as i64 ) < $ arr . len ( ) as i64 { let tmp = $ right ; *$ arr . get_unchecked_mut ( head as usize ) = std :: cmp :: min ( *$ arr . get_unchecked ( head as usize ) , tmp ) ; } } ; ( $ arr : expr , [ $ head : expr ] , $ op : tt , $ right : expr , max ) => { let head = $ head ; if 0 <= head as i64 && ( head as i64 ) < $ arr . len ( ) as i64 { let tmp = $ right ; *$ arr . get_unchecked_mut ( head as usize ) = std :: cmp :: max ( *$ arr . get_unchecked ( head as usize ) , tmp ) ; } } ; ( $ arr : expr , [ $ head : expr ] $ ( [ $ a : expr ] ) +, $ op : tt , $ right : expr , $ kind : ident ) => { let head = $ head ; if 0 <= head as i64 && ( head as i64 ) < $ arr . len ( ) as i64 { assign ! ( $ arr . get_unchecked_mut ( head as usize ) , $ ( [ $ a ] ) +, $ op , $ right , $ kind ) ; } } ; }
    #[macro_export]
    macro_rules! unwrap {
        ( $ arg : expr ) => {{
            let tmp = $arg;
            if tmp.is_none() {
                return;
            }
            tmp.unwrap()
        }};
    }
    #[macro_export]
    macro_rules! swap {
        ( $ a : expr , $ b : expr ) => {
            let tmp = $a;
            $a = $b;
            $b = tmp;
        };
    }
}
mod modulo {
    use crate::tiny_num_traits::ZeroOne;
    use std::marker::PhantomData;
    use std::ops::*;
    #[derive(Debug, PartialEq, Copy, Clone)]
    pub struct ModInt<T>(pub i64, PhantomData<*const T>);
    impl<T: ConstValue> ModInt<T> {
        pub fn new<U: ModIntCastable>(a: U) -> ModInt<T> {
            ModInt((a.to_long() % T::M + T::M) % T::M, PhantomData)
        }
        pub fn pow(self, mut n: i64) -> Self {
            let mut a = self;
            let mut res = Self::new(1);
            while n > 0 {
                if n & 1 == 1 {
                    res *= a;
                }
                a = a * a;
                n >>= 1;
            }
            res
        }
        pub fn inv(self) -> Self {
            self.pow(T::M - 2)
        }
    }
    pub trait ConstValue: Clone + Copy {
        const M: i64;
    }
    impl<T> std::fmt::Display for ModInt<T> {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            write!(f, "{}", self.0)
        }
    }
    impl<T: ConstValue, U: ModIntCastable> From<U> for ModInt<T> {
        fn from(n: U) -> Self {
            Self::new(n)
        }
    }
    impl<T: ConstValue> Add for ModInt<T> {
        type Output = ModInt<T>;
        fn add(self, other: ModInt<T>) -> ModInt<T> {
            Self::new(self.0 + other.0)
        }
    }
    impl<T: ConstValue> AddAssign for ModInt<T> {
        fn add_assign(&mut self, other: Self) {
            *self = self.add(other);
        }
    }
    impl<T: ConstValue> Sub for ModInt<T> {
        type Output = ModInt<T>;
        fn sub(self, other: ModInt<T>) -> ModInt<T> {
            Self::new(self.0 - other.0)
        }
    }
    impl<T: ConstValue> SubAssign for ModInt<T> {
        fn sub_assign(&mut self, other: Self) {
            *self = self.sub(other);
        }
    }
    impl<T: ConstValue> Mul for ModInt<T> {
        type Output = ModInt<T>;
        fn mul(self, other: ModInt<T>) -> ModInt<T> {
            Self::new(self.0 * other.0)
        }
    }
    impl<T: ConstValue> MulAssign for ModInt<T> {
        fn mul_assign(&mut self, other: Self) {
            *self = self.mul(other);
        }
    }
    impl<T: ConstValue> Div for ModInt<T> {
        type Output = ModInt<T>;
        fn div(self, other: ModInt<T>) -> ModInt<T> {
            self * other.inv()
        }
    }
    impl<T: ConstValue> DivAssign for ModInt<T> {
        fn div_assign(&mut self, other: Self) {
            *self = self.div(other);
        }
    }
    #[macro_export]
    macro_rules! modint {
        ( $ m : expr ) => {
            #[derive(Debug, PartialEq, Copy, Clone)]
            pub enum __M {}
            impl ConstValue for __M {
                const M: i64 = $m;
            }
            #[allow(dead_code)]
            type Z = ModInt<__M>;
        };
    }
    pub trait ModIntCastable {
        fn to_long(self) -> i64;
    }
    impl ModIntCastable for i64 {
        fn to_long(self) -> i64 {
            self
        }
    }
    impl ModIntCastable for usize {
        fn to_long(self) -> i64 {
            self as i64
        }
    }
    impl ModIntCastable for i32 {
        fn to_long(self) -> i64 {
            self as i64
        }
    }
    impl<T: ConstValue> ZeroOne for ModInt<T> {
        fn zero() -> Self {
            Self::new(0)
        }
        fn one() -> Self {
            Self::new(1)
        }
    }
}



Measured memory_bytes: 2180