#include<bits/stdc++.h>
using namespace std;


#define rep(i,n) for(int i=0;i<(n);i++)
#define pb push_back
#define all(v) (v).begin(),(v).end()
#define fi first
#define se second
typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;

template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}


template<uint32_t mod>
struct ModInt{
	uint32_t a;
    ModInt(int64_t x=0):a((x%mod+mod)%mod){}

	ModInt& operator+=(const ModInt &x){
		a+=x.a;
		if(a>=mod)a-=mod;
		return *this;
	}
	ModInt& operator-=(const ModInt &x){
		a+=mod-x.a;
        if(a>=mod)a-=mod;
		return *this;
	}
	ModInt& operator*=(const ModInt &x){
		a=(uint64_t)a*x.a%mod;
		return *this;
	}
	ModInt& operator/=(const ModInt &x){
		*this*=x.inv();
		return *this;
	}

	ModInt operator+(const ModInt x){return ModInt(*this)+=x;}
	ModInt operator-(const ModInt x){return ModInt(*this)-=x;}
	ModInt operator*(const ModInt x){return ModInt(*this)*=x;}
	ModInt operator/(const ModInt x){return ModInt(*this)/=x;}
	bool operator==(const ModInt x){return a==x.a;}
	bool operator!=(const ModInt x){return a!=x.a;}

	ModInt operator-(){return ModInt(0)-ModInt(*this);}
	inline ModInt pow(uint64_t ex)const{
		uint64_t x=a;
		uint64_t res=1;
		while(ex){
			if(ex&1)res=res*x%mod;
			x=x*x%mod;
			ex>>=1;
		}
		return ModInt(res);
	}

    inline ModInt inv()const{return pow(mod-2);}
};

template<uint32_t mod>
istream& operator>>(istream& in,ModInt<mod>& a){
	return (in>>a.a);
}
template<uint32_t mod>
ostream& operator<<(ostream& out,const ModInt<mod>& a){
	return (out<<a.a);
}
using mint=ModInt<998244353>;

template<class Mint,int32_t N>
struct ModIntTable{
	vector<Mint>facts,finvs,invs;
	ModIntTable():facts(N),finvs(N),invs(N){
		const uint32_t mod=Mint(-1).a+1;
		invs[1]=1;
		for(int i=2;i<N;i++)invs[i]=invs[mod%i]*(mod-mod/i);

		facts[0]=1;
		finvs[0]=1;
		for(int i=1;i<N;i++){
			facts[i]=facts[i-1]*i;
			finvs[i]=finvs[i-1]*invs[i];
		}
	}
	inline Mint fact(int n){return facts[n];}
	inline Mint finv(int n){return finvs[n];}
	inline Mint inv(int n){return invs[n];}
	inline Mint binom(int n,int k){return facts[n]*finvs[k]*finvs[n-k];}
};
ModIntTable<mint,1<<21>mtable;


template<class Mint,int32_t root>
struct NumberTheoreticTransform{
	static void ntt(vector<Mint>&f){
		int n=f.size();
        int s=__lg(n);

        for(int i=0,j=1;j<n-1;j++){
            for(int k=n>>1;k>(i^=k);k>>=1);
            if(i>j)swap(f[i],f[j]);
        }

        for(int m=1;m<=s;m++){
            Mint wr=Mint(root).pow(Mint(-1).a>>m);
            for(int i=0;i<n;i+=1<<m){
                Mint w=1;
                for(int j=0;j<1<<m-1;j++){
                    Mint f0=f[i+j],f1=w*f[i+j+(1<<m-1)];
                    f[i+j]=f0+f1;
                    f[i+j+(1<<m-1)]=f0-f1;
                    w*=wr;
                }
            }
        }
	}

    static void intt(vector<Mint>&f){
        reverse(f.begin()+1,f.end());
        ntt(f);
        Mint in=Mint(f.size()).inv();
        for(int i=0;i<f.size();i++)f[i]*=in;
    }

	static vector<Mint>convolute(const vector<Mint>&A,const vector<Mint>&B){
        if(A.size()==0||B.size()==0)return {};
        int n=1<<__lg(A.size()+B.size()-2)+1;
        
        vector<Mint>a=A,b=B;
        a.resize(n);b.resize(n);
        ntt(a);
        ntt(b);
        for(int i=0;i<n;i++)a[i]*=b[i];
        intt(a);
        a.resize(A.size()+B.size()-1);
        return a;
    }
};
using NTT=NumberTheoreticTransform<mint,3>;


const uint32_t mod=998244353;
const mint prim_root=3;


static const int LG=21;
mint roots[1<<(LG+1)],iroots[1<<(LG+1)];
struct PrepareRoots{
	PrepareRoots(){
		rep(w,LG+1){
			const int s=(1<<w)-1;
			const mint g=prim_root.pow((mod-1)/(1<<w)),ig=g.inv();
			mint p=1,ip=1;
			rep(i,1<<w){
				roots[s+i]=p;p*=g;
				iroots[s+i]=ip;ip*=ig;
			}
		}
	}
} PrepareRootsDummy;

void broken_fmt(vector<mint>&f){
	const int n=f.size();
	for(int b=n/2;b>=1;b/=2){
		for(int i=0;i<n;i+=b*2){
			rep(j,b){
				mint tmp=f[i+j]-f[i+j+b];
				f[i+j]+=f[i+j+b];
				f[i+j+b]=tmp*roots[b*2-1+j];
			}
		}
	}
}

void broken_ifmt(vector<mint>&f){
	const int n=f.size();
	for(int b=1;b<=n/2;b*=2){
		for(int i=0;i<n;i+=b*2){
			rep(j,b){
				f[i+j+b]*=iroots[b*2-1+j];
				mint tmp=f[i+j]-f[i+j+b];
				f[i+j]+=f[i+j+b];
				f[i+j+b]=tmp;
			}
		}
	}
	mint in=mint(n).inv();
	rep(i,n)
		f[i]*=in;
}

void inplace_fmt(vector<mint>&f,const bool i=false){
	if(!i)broken_fmt(f);
	else broken_ifmt(f);
}



vector<mint> multiply(vector<mint> x,vector<mint> y,bool same=false){
	int n=x.size()+y.size()-1;
	int s=1;
	while(s<n)s*=2;
	x.resize(s);inplace_fmt(x,false);
	if(!same){
		y.resize(s);inplace_fmt(y,false);
	}else
		y=x;
	rep(i,s)
		x[i]*=y[i];
	inplace_fmt(x,true);x.resize(n);
	return x;
}
 
template<class Mint>
struct NTTFriendlyPoly{
	void ntt(vector<Mint>&f){
		int n=f.size();
        int s=__lg(n);

        for(int i=0,j=1;j<n-1;j++){
            for(int k=n>>1;k>(i^=k);k>>=1);
            if(i>j)swap(f[i],f[j]);
        }

        for(int m=1;m<=s;m++){
            Mint wr=Mint(3).pow(Mint(-1).a>>m);
            for(int i=0;i<n;i+=1<<m){
                Mint w=1;
                for(int j=0;j<1<<m-1;j++){
                    Mint f0=f[i+j],f1=w*f[i+j+(1<<m-1)];
                    f[i+j]=f0+f1;
                    f[i+j+(1<<m-1)]=f0-f1;
                    w*=wr;
                }
            }
        }
	}

    void intt(vector<Mint>&f){
        reverse(f.begin()+1,f.end());
        ntt(f);
        Mint in=Mint(f.size()).inv();
        for(int i=0;i<f.size();i++)f[i]*=in;
    }

	vector<Mint>convolute(const vector<Mint>&A,const vector<Mint>&B){
        if(A.size()==0||B.size()==0)return {};
        int n=1<<__lg(A.size()+B.size()-2)+1;
        
        vector<Mint>a=A,b=B;
        a.resize(n);b.resize(n);
        ntt(a);
        ntt(b);
        for(int i=0;i<n;i++)a[i]*=b[i];
        intt(a);
        a.resize(A.size()+B.size()-1);
        return a;
    }

	vector<Mint>v;
	template<class...Args>
	NTTFriendlyPoly(Args...args):v(args...){}
 
	NTTFriendlyPoly(const initializer_list<Mint>&in):v(in.begin(),in.end()){}
 
	int size()const{return v.size();}
 
	inline Mint coef(const int i)const{return (i<v.size())?v[i]:Mint(0);}
 
	NTTFriendlyPoly operator+(const NTTFriendlyPoly &x){
		int n=max(size(),x.size());
		NTTFriendlyPoly<Mint>res(n);
		for(int i=0;i<n;i++)res[i]=coef(i)+x.coef(i);
		return res;
	}
	NTTFriendlyPoly operator-(const NTTFriendlyPoly &x){
		int n=max(size(),x.size());
		NTTFriendlyPoly<Mint>res(n);
		for(int i=0;i<n;i++)res[i]=coef(i)-x.coef(i);
		return res;
	}
	NTTFriendlyPoly operator*(const NTTFriendlyPoly& x){
		return multiply(v,x.v);
	}
	NTTFriendlyPoly operator*(const Mint& x){
		int n=size();
		vector<Mint>res(n);
		for(int i=0;i<n;i++)res[i]=v[i]*x;
		return res;
	}
	NTTFriendlyPoly operator/(const Mint& x){
		return (*this)*x.inv();
	}
 
	NTTFriendlyPoly& operator+=(const NTTFriendlyPoly& x){return *this=(*this)+x;}
	NTTFriendlyPoly& operator-=(const NTTFriendlyPoly& x){return *this=(*this)-x;}
	NTTFriendlyPoly& operator*=(const NTTFriendlyPoly& x){return *this=(*this)*x;}
	NTTFriendlyPoly& operator*=(const Mint& x){return *this=(*this)*x;}
	NTTFriendlyPoly& operator/=(const Mint& x){return *this=(*this)/x;}
	NTTFriendlyPoly operator-(){return NTTFriendlyPoly()-*this;}
 
    NTTFriendlyPoly pre(int n){
        NTTFriendlyPoly<Mint>res(n);
		for(int i=0;i<n&&i<size();i++)res[i]=v[i];
		return res;
    }
    NTTFriendlyPoly rev(){
        vector<Mint>res=v;
		while(res.size()&&res.back()==0)res.pop_back();
        reverse(res.begin(),res.end());
        return res;
    }
    NTTFriendlyPoly diff(int n){
        NTTFriendlyPoly<Mint>res(n);
        for(int i=1;i<size()&&i<=n;i++)res[i-1]=v[i]*i;
        return res;
    }
    NTTFriendlyPoly inte(int n){
        NTTFriendlyPoly<Mint>res(n);
        for(int i=0;i<size()&&i+1<n;i++)res[i+1]=v[i]*mtable.inv(i+1);
        return res;
    }

    NTTFriendlyPoly inv(int n){
        vector<mint>res{coef(0).inv()};

        for(int d=1;d<n;d<<=1){
            vector<Mint>f(2*d),g(2*d);
            for(int j=0;j<2*d;j++)f[j]=coef(j);
            for(int j=0;j<d;j++)g[j]=res[j];
            
            inplace_fmt(f);inplace_fmt(g);
            for(int j=0;j<2*d;j++)f[j]*=g[j];
            inplace_fmt(f,true);
            for(int j=0;j<d;j++){
                f[j]=0;
                f[j+d]=-f[j+d];
            }
            inplace_fmt(f);
            for(int j=0;j<2*d;j++)f[j]*=g[j];
            inplace_fmt(f,true);
            for(int j=0;j<d;j++)f[j]=res[j];
            res=f;
        }
        return NTTFriendlyPoly(res).pre(n);
    }
    
    
    NTTFriendlyPoly inv2(int n){
        NTTFriendlyPoly res{coef(0).inv()};
        for(int i=1;i<n;i*=2){
            res=(res*Mint(2)-res*res*pre(2*i)).pre(2*i);
        }
        return res.pre(n);
    }
    
    

	NTTFriendlyPoly exp(int n){
		NTTFriendlyPoly f0{1},g0{1};
		vector<Mint>F0{1};
		for(int d=1;d<n;d<<=1){
			vector<Mint>G0=g0.v;
			inplace_fmt(G0);
			vector<Mint>Delta(d);
			for(int j=0;j<d;j++)Delta[j]=F0[j]*G0[j];
			inplace_fmt(Delta,true);
			Delta[0]-=1;
			NTTFriendlyPoly delta(2*d);
			for(int j=0;j<d;j++)delta[d+j]=Delta[j];		
			
			NTTFriendlyPoly epsilon(2*d);
			
		
			
			vector<Mint>DF0=f0.diff(d-1).v;DF0.push_back(0);
			inplace_fmt(DF0);
			for(int j=0;j<d;j++)DF0[j]*=G0[j];
			inplace_fmt(DF0,true);
			for(int j=0;j<d-1;j++){
				epsilon[j]+=coef(j+1)*(j+1);
				epsilon[j+d]+=DF0[j]-coef(j+1)*(j+1);
			}
			epsilon[d-1]+=DF0[d-1];


			Delta=delta.v;
			inplace_fmt(Delta);
			vector<Mint>DH0=diff(d-1).v;DH0.resize(2*d);
			inplace_fmt(DH0);
			for(int j=0;j<2*d;j++)Delta[j]*=DH0[j];
			inplace_fmt(Delta,true);
			for(int j=0;j<d;j++)epsilon[j+d]-=Delta[j+d];
		

			epsilon=epsilon.inte(2*d)-pre(2*d);
			
			vector<Mint>Epsilon=epsilon.v;
			inplace_fmt(Epsilon);
			rep(j,d)DH0[j]=f0[j],DH0[j+d]=0;
			inplace_fmt(DH0);
			rep(j,2*d)Epsilon[j]*=DH0[j];
			inplace_fmt(Epsilon,true);
			f0.v.resize(2*d);
			rep(j,d)f0[j+d]-=Epsilon[j+d];
			//f0=(f0-epsilon*f0).pre(2*d);
			
			G0.resize(2*d);
			rep(j,d)G0[j]=g0[j];
			inplace_fmt(G0);
			F0=f0.v; 
			inplace_fmt(F0);
			vector<Mint>T(2*d);rep(j,2*d)T[j]=F0[j]*G0[j];
			inplace_fmt(T,true);
			rep(j,d){
				T[j]=0;
				T[j+d]=-T[j+d];
			}
			inplace_fmt(T);
			rep(j,2*d)T[j]*=G0[j];
			inplace_fmt(T,true);
			rep(j,d)T[j]=g0[j];
			g0=T;
		}
		return f0.pre(n);
	}

    NTTFriendlyPoly exp2(int n){
        NTTFriendlyPoly f{1};
        for(int i=1;i<n;i*=2){
            f=(f*(pre(2*i)-f.log(2*i))+f).pre(2*i);
        }
        return f.pre(n);
    }

	NTTFriendlyPoly exp3(int n){
		NTTFriendlyPoly f{1},g{1};
		for(int d=1;d<n;d<<=1){
			g=g*Mint(2)-(g*g*f).pre(d);

			NTTFriendlyPoly q=diff(d-1);
			q=q+g*(f.diff(d-1)-f*q).pre(2*d-1);
			f=f+(f*(pre(2*d)-q.inte(2*d))).pre(2*d);
		}
		return f.pre(n);
	}


 
    NTTFriendlyPoly log(int n){
        return (diff(n-1)*inv(n-1)).inte(n);
    }
 
    NTTFriendlyPoly pow(int n,mint k){
		auto res=log(n);
		res*=k;
		return res.exp(n);
	}
	Mint& operator[](const int i){return v[i];}
};
using poly=NTTFriendlyPoly<mint>;
 
template<class Mint>
ostream& operator<<(ostream& ost,NTTFriendlyPoly<Mint>a){
    for(int i=0;i<a.size();i++){
        if(i)cout<<" ";
        cout<<a.v[i];
    }
    return ost;
}

signed main(){
	int N,M;
	cin>>N>>M;
 
	poly p(N+1);
 
	auto in=mint(N+1).inv();
	for(int i=0;i<=N;i++){
		p[i]=mtable.finv(i)*in*(N+1-i);
	}

	p=p.pow(N+1,M);
 
	mint ans=0;
	for(int i=0;i<=N;i++){
		ans+=p[i]*mtable.finv(N-i);
	}
	ans*=mtable.fact(N);
	ans*=mint(N+1).pow(M);
	cout<<ans<<endl;
	return 0;
}

Measured memory_bytes: 91648