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

#define int long long

#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 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>;

 
template<class Mint,class Convoluter>
struct NTTFriendlyPoly{
	vector<Mint>v;
    inline void normalize(){
        while(v.size()&&v.back()==0)v.pop_back();
    }
	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());
		vector<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());
		vector<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 Convoluter::convolute(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){
        return {v.begin(),v.begin()+min(n,size())};
    }
    NTTFriendlyPoly rev(){
        vector<Mint>res=v;
        reverse(res.begin(),res.end());
        return res;
    }
    NTTFriendlyPoly diff(int n){
        vector<Mint>res(n);
        for(int i=1;i<size()&&i<=n;i++)res[i-1]=coef(i)*i;
        return res;
    }
    NTTFriendlyPoly inte(int n){
        vector<Mint>res(n);
        for(int i=0;i<size()&&i+1<n;i++)res[i+1]=coef(i)/(i+1);
        return res;
    }

    NTTFriendlyPoly inv(int n){
        NTTFriendlyPoly 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];
            
            Convoluter::ntt(f);Convoluter::ntt(g);
            for(int j=0;j<2*d;j++)f[j]*=g[j];
            Convoluter::intt(f);
            for(int j=0;j<d;j++){
                f[j]=0;
                f[j+d]=-f[j+d];
            }
            Convoluter::ntt(f);
            for(int j=0;j<2*d;j++)f[j]*=g[j];
            Convoluter::intt(f);
            for(int j=0;j<d;j++)f[j]=res[j];
            res=f;
        }
        return 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;
			Convoluter::ntt(G0);
			vector<Mint>Delta(d);
			for(int j=0;j<d;j++)Delta[j]=F0[j]*G0[j];
			Convoluter::intt(Delta);
			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);
			Convoluter::ntt(DF0);
			for(int j=0;j<d;j++)DF0[j]*=G0[j];
			Convoluter::intt(DF0);
			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;
			Convoluter::ntt(Delta);
			vector<Mint>DH0=diff(d-1).v;DH0.resize(2*d);
			Convoluter::ntt(DH0);
			for(int j=0;j<2*d;j++)Delta[j]*=DH0[j];
			Convoluter::intt(Delta);
			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;
			Convoluter::ntt(Epsilon);
			rep(j,d)DH0[j]=f0[j],DH0[j+d]=0;
			Convoluter::ntt(DH0);
			rep(j,2*d)Epsilon[j]*=DH0[j];
			Convoluter::intt(Epsilon);
			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];
			Convoluter::ntt(G0);
			F0=f0.v; 
			Convoluter::ntt(F0);
			vector<Mint>T(2*d);rep(j,2*d)T[j]=F0[j]*G0[j];
			Convoluter::intt(T);
			rep(j,d){
				T[j]=0;
				T[j+d]=-T[j+d];
			}
			Convoluter::ntt(T);
			rep(j,2*d)T[j]*=G0[j];
			Convoluter::intt(T);
			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,NTT>;
 
template<class Mint,class Convoluter>
ostream& operator<<(ostream& ost,NTTFriendlyPoly<Mint,Convoluter>a){
    for(int i=0;i<a.size();i++){
        if(i)cout<<" ";
        cout<<a.v[i];
    }
    return ost;
}

template<class Mint>
struct Combinations{
	int N;
	vector<Mint>facts,finvs,invs;
	Combinations(int n):N(n),facts(n),finvs(n),invs(n){
		facts[0]=finvs[0]=1;
		for(int i=1;i<N;i++){
			facts[i]=facts[i-1]*i;
			invs[i]=Mint(i).inv();
			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];}
};
Combinations<mint>C(555555);
 
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]=C.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]*C.finv(N-i);
	}
	ans*=C.fact(N);
	ans*=mint(N+1).pow(M);
	cout<<ans<<endl;
	return 0;
}

Measured memory_bytes: 38492