#ifndef MYLOCAL //# pragma GCC target("avx2")//yukiではNG # pragma GCC optimize("O3") # pragma GCC optimize("unroll-loops") #endif #if defined(NDEBUG) #undef NDEBUG #endif #include "bits/stdc++.h" using namespace std; using ll=long long; using dd=long double; using pll=pair; using tll=tuple; using qll=tuple; using namespace chrono; constexpr ll INF = 1201001001001001001; struct Fast{ Fast(){ cin.tie(0); ios::sync_with_stdio(false); cout<::max_digits10); } } fast; #define EXPAND( x ) x//VS用おまじない #define overload3(_1,_2,_3,name,...) name #define overload4(_1,_2,_3,_4,name,...) name #define overload5(_1,_2,_3,_4,_5,name,...) name #define rep1(N) for (ll dmyi = 0; dmyi < (N); dmyi++) #define rep2(i, N) for (ll i = 0; i < (N); i++) #define rep3(i, S, E) for (ll i = (S); i <= (E); i++) #define rep4(i, S, E, t) for (ll i = (S); i <= (E); i+=(t)) #define rep(...) EXPAND(overload4(__VA_ARGS__,rep4,rep3,rep2,rep1)(__VA_ARGS__)) #define dep3(i, E, S) for (ll i = (E); i >= (S); i--) #define dep4(i, E, S, t) for (ll i = (E); i >= (S); i-=(t)) #define dep(...) EXPAND(overload4(__VA_ARGS__, dep4, dep3,_,_)(__VA_ARGS__)) #define ALL1(v) (v).begin(), (v).end() #define ALL2(v,E) (v).begin(), (v).begin()+((E)+1) #define ALL3(v,S,E) (v).begin()+(S), (v).begin()+((E)+1) #define all(...) EXPAND(overload3(__VA_ARGS__, ALL3, ALL2, ALL1)(__VA_ARGS__)) template inline bool chmax(T &a, T b) { if (a < b) { a = b; return true; }return false; } template inline bool chmin(T &a, T b) { if (a > b) { a = b; return true; }return false; } template [[nodiscard]] inline T limithi(T a,T b){ return min(a,b); } template [[nodiscard]] inline T limitlo(T a,T b){ return max(a,b); } template inline bool chlimithi(T &a,T b){ return chmin(a,b); } template inline bool chlimitlo(T &a,T b){ return chmax(a,b); } template inline auto maxe(T &&v,ll S,ll E){ return *max_element(all(v,S,E)); } template inline auto maxe(T &&v){ return *max_element(all(v)); } template inline auto mine(T &&v,ll S,ll E){ return *min_element(all(v,S,E)); } template inline auto mine(T &&v){ return *min_element(all(v)); } template::type::value_type> inline U sum(T &&v,ll S,ll E) {return accumulate(all(v,S,E),U());} template inline auto sum(T &&v) {return sum(v,0,v.end()-v.begin()-1);} template inline ll sz(T &&v){ return (ll)v.size(); } //cin struct cinutil{ template static void cin1core(T &a){ cin>>a; } template static void cin1core(pair &a){ cin1core(a.first),cin1core(a.second); } template static void cin1core(tuple &a){ cinTplRec,sizeof...(Args)-1>()(a); } template static void cin1core(array &a){ for (int i=0; i<(int)N; ++i) cin>>a[i]; } private: template struct cinTplRec{ void operator()(Tpl &a){ cinTplRec()(a); cin1core(get(a)); } }; template struct cinTplRec{ void operator()(Tpl &a){ cin1core(get<0>(a)); } }; }; template T cin1(){ T a; cinutil::cin1core(a); return a; } template tuple cins(){ return cin1>(); } //cout template inline ostream &operator<<(ostream &os,const pair &a){ return os << a.first << ' ' << a.second; } template inline ostream &operator<<(ostream &os,const tuple &a){ return os << get<0>(a) << ' ' << get<1>(a) << ' ' << get<2>(a); } template inline ostream &operator<<(ostream &os,const tuple &a){ return os << get<0>(a) << ' ' << get<1>(a) << ' ' << get<2>(a) << ' ' << get<3>(a); } template inline ostream &operator<<(ostream &os,const vector &a){ for (ll i=0; i<(ll)a.size(); i++) os<<(i>0?" ":"")<(system_clock::now()-st).count()/1000;} } timeget; template struct mll_{ using Int = long long; using ll = long long; ll val_=0; /*---- utility ----*/ mll_ &norm(){ return normR().normS(); }//正規化 mll_ &normR(){ val_%=MOD; return *this; }//剰余正規化のみ mll_ &normS(){ if (val_<0) val_+=MOD; return *this; }//正負正規化のみ mll_ &normP(){ if (val_>=MOD) val_-=MOD; return *this; }//加算時正規化 mll_ &invsg(){ val_=-val_; return normS(); }//正負反転 ll modinv(int a){//a^-1 mod MOD int ypre=0,y=1,apre=MOD; while (a>1){ int t=apre/a; apre-=a*t,swap(a,apre); ypre-=y*t,swap(y,ypre); } return y<0 ? y+MOD : y; } /*---- I/F ----*/ mll_(){} mll_(ll v): val_(v){ norm(); } mll_(ll v,bool b): val_(v){} //正規化無のコンストラクタ Int val()const{ return (Int)val_; } bool isnone() const { return val_==-1; } //true:値なし mll_ &none() { val_=-1; return *this; } //値なしにする mll_ &inv(){ val_=modinv((int)val_); return *this; } mll_ &operator+=(mll_ b){ val_+=b.val_; return normP(); } mll_ &operator-=(mll_ b){ val_-=b.val_; return normS(); } mll_ &operator*=(mll_ b){ val_*=b.val_; return normR(); } mll_ &operator/=(mll_ b){ return *this*=b.inv(); } mll_ &operator+=(ll b){ return *this+=mll_(b); } mll_ &operator-=(ll b){ return *this-=mll_(b); } mll_ &operator*=(ll b){ return *this*=mll_(b); } mll_ &operator/=(ll b){ return *this/=mll_(b); } mll_ operator-()const{ return mll_(*this).invsg(); } mll_ operator+(mll_ b)const{ return mll_(*this)+=b; } mll_ operator-(mll_ b)const{ return mll_(*this)-=b; } mll_ operator*(mll_ b)const{ return mll_(*this)*=b; } mll_ operator/(mll_ b)const{ return mll_(*this)/=b; } mll_ operator+(ll b)const{ return mll_(*this)+=b; } mll_ operator-(ll b)const{ return mll_(*this)-=b; } mll_ operator*(ll b)const{ return mll_(*this)*=b; } mll_ operator/(ll b)const{ return mll_(*this)/=b; } friend mll_ operator+(ll a,mll_ b){ return b+a; } friend mll_ operator-(ll a,mll_ b){ return -b+a; } friend mll_ operator*(ll a,mll_ b){ return b*a; } friend mll_ operator/(ll a,mll_ b){ return mll_(a)/b; } bool operator==(mll_ b)const{ return val_==b.val_; } bool operator!=(mll_ b)const{ return val_!=b.val_; } bool operator==(ll b)const{ return *this==mll_(b); } bool operator!=(ll b)const{ return *this!=mll_(b); } friend bool operator==(ll a,mll_ b){ return mll_(a)==b; } friend bool operator!=(ll a,mll_ b){ return mll_(a)!=b; } friend ostream &operator<<(ostream &os,mll_ a){ return os << a.val_; } friend istream &operator>>(istream &is,mll_ &a){ return is >> a.val_; } mll_ pow(ll k)const{ mll_ ret(1,false),a(*this); for (; k>0; k>>=1,a*=a) if (k&1)ret*=a; return ret; } static constexpr int mod() { return MOD; } //enum{ modll=MOD }; }; template struct Vector: vector{ using Int = long long; using vT=vector; using cvT=const vector; using cT=const T; using vT::vT; //親クラスのコンストラクタの隠蔽を回避 using vT::begin,vT::end,vT::insert,vT::erase; auto it(Int i){ return begin()+i; } auto it(Int i)const{ return begin()+i; } Vector(cvT& b):vT(b){} Vector(vT&& b):vT(move(b)){} Vector(int n,cT& x):vT(n,x){}// ┬ 型推論のためラッパー Vector(long long n,cT& x):vT(n,x){} template Vector(const Vector& b):vT(b.begin(),b.end()){} template Vector(const vector& b):vT(b.begin(),b.end()){} Vector(Int n,T s,T d){ iota(n,s,d); } Vector(Int n,function g):vT(n){ for(Int i=0;i &b){ return *this+=(cvT&)b; } Vector &operator-=(const Vector &b){ return *this-=(cvT&)b; } Vector &operator*=(const Vector &b){ return *this*=(cvT&)b; } Vector &operator/=(const Vector &b){ return *this/=(cvT&)b; } Vector &operator%=(const Vector &b){ return *this%=(cvT&)b; } Vector operator+(cvT &b){ return Vector(*this)+=b; } Vector operator-(cvT &b){ return Vector(*this)-=b; } Vector operator*(cvT &b){ return Vector(*this)*=b; } Vector operator/(cvT &b){ return Vector(*this)/=b; } Vector operator%(cvT &b){ return Vector(*this)%=b; } Vector operator+(const Vector &b){ return Vector(*this)+=b; } Vector operator-(const Vector &b){ return Vector(*this)-=b; } Vector operator*(const Vector &b){ return Vector(*this)*=b; } Vector operator/(const Vector &b){ return Vector(*this)/=b; } Vector operator%(const Vector &b){ return Vector(*this)%=b; } template Vector &operator+=(S x){ for(T &e: *this) e+=x; return *this; } template Vector &operator-=(S x){ for(T &e: *this) e-=x; return *this; } template Vector &operator*=(S x){ for(T &e: *this) e*=x; return *this; } template Vector &operator/=(S x){ for(T &e: *this) e/=x; return *this; } template Vector &operator%=(S x){ for(T &e: *this) e%=x; return *this; } template Vector operator+(S x)const{ return Vector(*this)+=x; } template Vector operator-(S x)const{ return Vector(*this)-=x; } template Vector operator*(S x)const{ return Vector(*this)*=x; } template Vector operator/(S x)const{ return Vector(*this)/=x; } template Vector operator%(S x)const{ return Vector(*this)%=x; } Vector &operator--(int){ return *this-=1; } Vector &operator++(int){ return *this+=1; } Vector operator-()const{ return Vector(*this)*=-1; } template friend Vector operator-(S x,const Vector &a){ return -a+=x; } T& at(Int i){ assert(i>=0); if(n()<=i)vT::resize(i+1); return vT::operator[](i); } Vector slice(Int l,Int r,Int d=1)const{ Vector ret; for(Int i=l;(d>0&&i<=r)||(d<0&&r<=i);i+=d) ret.push_back((*this)[i]); return ret; } Int size()const{ return (Int)vT::size(); } Int n()const{ return size(); } Vector &push_back(cT& x,Int n=1){ for(Int i=0;iinsert(0,x,n); return *this; } Vector &pop_front(Int n=1){ erase(0,n-1); return *this; } T pull_back(){ T x=move(vT::back()); vT::pop_back(); return x; } T pull_front(){ T x=move(vT::front()); erase(0); return x; } Vector &insert(Int i,cT& x,Int n=1){ insert(it(i),n,x); return *this; } Vector &insert(Int i,cvT& b){ insert(it(i),b.begin(),b.end()); return *this; } Vector &erase(Int i){ erase(it(i)); return *this; } Vector &erase(Int l,Int r){ erase(it(l),it(r+1)); return *this; } Vector &erase(const Vector &idxs){ for (Int I=0; In(); copy(it(l),it(r),it(l-I-1));//[l,r)を前にI+1個ずらす } vT::resize(this->n()-idxs.n()); return *this; } Vector &eraseall(cT& x){ return eraseall(0,size()-1,x); } Vector &eraseall(Int l,Int r,cT& x){ erase(remove(it(l),it(r+1),x),it(r+1)); return *this; } template Vector &eraseif(Pr pr){ return eraseif(0,size()-1,pr); } template Vector &eraseif(Int l,Int r,Pr pr){ erase(remove_if(it(l),it(r+1),pr),it(r+1)); return *this; } Vector &concat(cvT &b,Int n=1){ cvT B = (&b==this) ? *this : vT{}; for(int i=0;iinsert(size(),(&b==this)?B:b); return *this; } Vector repeat(Int n){ return Vector{}.concat(*this,n); } Vector &reverse(Int l=0,Int r=-1){ r+=r<0?size():0; std::reverse(it(l),it(r+1)); return *this; } Vector &rotate(Int m){ return rotate(0,size()-1,m); } Vector &rotate(Int l,Int r,Int m){ std::rotate(it(l),it(m),it(r+1)); return *this; } Vector &sort(Int l=0,Int r=-1){ r+=r<0?size():0; std::sort(it(l),it(r+1)); return *this; } Vector &rsort(Int l=0,Int r=-1){ return sort(l,r).reverse(l,r); } template Vector &sort(Pr pr){ return sort(0,size()-1,pr); } template Vector &sort(Int l,Int r,Pr pr){ std::sort(it(l),it(r+1),pr); return *this; } template Vector &sortbykey(Int l=0,Int r=-1){ r+=r<0?size():0; sort(l,r,[](cT &x,cT &y){return get(x)(y);}); return *this; } Vector &uniq(){ erase(unique(begin(),end()),end()); return *this; } Vector &sortq(){ return sort().uniq(); } Vector &fill(cT& x){ return fill(0,size()-1,x); } Vector &fill(Int l,Int r,cT& x){ std::fill(it(l),it(r+1),x); return *this; } Vector ©(Int i,cvT &b,Int n=1){//A[i]スタートでbをn回分コピー for (int t=0; t=size()) return *this; if (i>=0) (*this)[i]=b[j]; i++; } return *this; } template Vector &iota(Int n,T s=0,S d=1){ vT::resize(n); if(n==0) return *this; (*this)[0]=s; for(int i=1;i Int countif(Pr pr)const{ return countif(0,size()-1,pr); } template Int countif(Int l,Int r,Pr pr)const{ return Int(count_if(it(l),it(r+1),pr)); } Int find(cT& x)const{ return find(0,size()-1,x); } Int find(Int l,Int r,cT& x)const{ return Int(std::find(it(l),it(r+1),x)-begin()); } Int rfind(cT& x)const{ return rfind(0,size()-1,x); } Int rfind(Int l,Int r,cT& x)const{ for (int i=r;i>=l;--i) if ((*this)[i]==x) return i; return l-1; } template Int findif(Pr pr)const{ return findif(0,size()-1,pr); } template Int findif(Int l,Int r,Pr pr)const{ return Int(find_if(it(l),it(r+1),pr)-begin()); } Vector findall(cT& x)const{ return findall(0,size()-1,x); } Vector findall(Int l,Int r,cT& x)const{ return findallif(l,r,[&](cT& y){return y==x;}); } template Vector findallif(Pr pr)const{ return findallif(0,size()-1,pr); } template Vector findallif(Int l,Int r,Pr pr)const{ Vector ret; for(Int i=l;i<=r;++i) if(pr((*this)[i])) ret.push_back(i); return ret; } Int flooridx(cT& x)const{ return Int(upper_bound(begin(),end(),x)-begin()-1); } Int ceilidx(cT& x)const{ return Int(lower_bound(begin(),end(),x)-begin()); } Int leftnmof(cT& x)const{ return flooridx(x)+1; } Int rightnmof(cT& x)const{ return size()-ceilidx(x); } bool contains(cT& x)const{ Int i=flooridx(x); return i>=0 && (*this)[i]==x; } template Int flooridx(cT& x,Pr pr)const{ return Int(upper_bound(begin(),end(),x,pr)-begin()-1); } template Int ceilidx(cT& x,Pr pr)const{ return Int(lower_bound(begin(),end(),x,pr)-begin()); } template Int leftnmof(cT& x,Pr pr)const{ return flooridx(x,pr)+1; } template Int rightnmof(cT& x,Pr pr)const{ return size()-ceilidx(x,pr); } template bool contains(cT& x,Pr pr)const{ Int i=flooridx(x,pr); return i>=0 && (*this)[i]==x; } template using VV = Vector>; template using sVV = vector>; template using VVV = Vector>; template using sVVV = vector>; template using VVVV = Vector>; template using sVVVV = vector>; template using VVVVV = Vector>; template using sVVVVV = vector>; auto tostd()const{ return tov(*this); } template static vector tov(const Vector&v){ return v; } template static sVV tov(const VV &v){ sVV ret; for(auto&& e:v) ret.push_back(e); return ret; } template static sVVV tov(const VVV &v){ sVVV ret; for(auto&& e:v) ret.push_back(e.tostd()); return ret; } template static sVVVV tov(const VVVV &v){ sVVVV ret; for(auto&& e:v) ret.push_back(e.tostd()); return ret; } template static sVVVVV tov(const VVVVV &v){ sVVVVV ret; for(auto&& e:v) ret.push_back(e.tostd()); return ret; } }; #if 0 #define MODLL (1000000007LL) #else #define MODLL (998244353LL) #endif using mll = mll_; //using mll = fraction; namespace SolvingSpace{ template using vector = Vector; using vll=vector< ll>; using vmll=vector< mll>; using vdd=vector< dd>; using vvll=vector< vll>; using vvmll=vector< vmll>; using vvdd=vector< vdd>; using vvvll=vector< vvll>; using vvvmll=vector< vvmll>; using vvvdd=vector< vvdd>; using vvvvll=vector; using vvvvmll=vector; using vvvvdd=vector; using vpll=vector< pll>; using vtll=vector< tll>; using vqll=vector< qll>; using vvpll=vector< vpll>; using vvtll=vector< vtll>; using vvqll=vector< vqll>; using vss=vector; template vector cinv(ll nm){ return vector(nm,[](ll i){ (void)i; return cin1(); }); } template vector> cinvv(ll H,ll W){ return vector>(H,[&](ll i){ (void)i; return cinv(W); }); } /*■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■*/ template struct rangeNd{ using Int = long long; using NInt = array; NInt sv,ev,lv,dv; //各変数の初期値,終了値,項数,公差(通常±1) Int size_=1; NInt cyclemask; rangeNd(const NInt &sv_,const NInt &ev_,Int cycle=-1): sv(sv_),ev(ev_){ for (ll i=0; i SELDx()const{ return SELDof(0); } tuple SELDy()const{ return SELDof(1); } tuple SELDz()const{ return SELDof(2); } tuple SELDw()const{ return SELDof(3); } array rngs()const{ return {sv,dv}; } NInt ls()const{ return lv; } NInt v2i(const NInt &vx)const{ NInt ret; for (Int i=0; iInt{ Int id=0; for (Int i=0; iNInt{ NInt ret; for (Int i=DIM-1; i>=0; --i){ Int s=sv[i],l=lv[i],d=dv[i],nid=id/l,xx=id-nid*l; ret[i]=s+xx*d; id=nid; } return ret; }; } bool out(const NInt &vx){ for (Int i=0; i=dMn; --d){ if (vx[d]==ev[d]) vx[d]=sv[d]; else{ vx[d]+=dv[d]; return true; } } return false; } private: tuple SELDof(Int i)const{ if (i>=DIM) return {-1,-1,-1,-1}; return {sv[i],ev[i],lv[i],dv[i]}; } static Int sign(Int x){ return x>=0 ? 1 : -1; } }; template struct PushBasedDP{ using Int = long long; using ll = long long; Ope ope; //配るときの演算 Tran tran; ToID toID; FromID fromID; VAL ini,dmy; //ini:dpテーブルの初期値 const bool isinf; //true:iniは配らない(ini=±INFを想定) vector dp_; bool autoResize = true; bool nextdp = false; //true:nextDP //-------- コンストラクタ -------- PushBasedDP(STATE,VAL,Ope ope_,Tran tran_,ToID toID_,FromID fromID_, VAL ini_,bool isinf_) : ope(ope_),tran(tran_),toID(toID_),fromID(fromID_), ini(ini_),dmy(ini_),isinf(isinf_){ } //事前メモリ確保用コンストラクタ template PushBasedDP(STATE,VAL,Ope ope_,Tran tran_,ToID toID_, FromID fromID_,VAL ini_,bool isinf_,const RNG &rng) : ope(ope_),tran(tran_),toID(toID_),fromID(fromID_), ini(ini_),dmy(ini_),isinf(isinf_), dp_(rng.isCycle() ? rng.csize()*rng.cycle() : rng.size(),ini), autoResize(false),nextdp(rng.isCycle()){ } //-------- アクセス・計算実行 -------- template VAL &operator()(Args&&... args){ return Dp(STATE{args...}); } template void calc(Args&&... args){ calcSt({args...}); } template void calcall(const RNG &rng){ if (nextdp) calcallNextDp(rng); else calcallNormal(rng); } using vVAL = vector< VAL>; using vvVAL = vector< vVAL>; using vvvVAL = vector; using vvvvVAL = vector; vVAL tov(array ls){ return tov(ls[0]); } vvVAL tov(array ls){ return tov(ls[0],ls[1]); } vvvVAL tov(array ls){ return tov(ls[0],ls[1],ls[2]); } vvvvVAL tov(array ls){ return tov(ls[0],ls[1],ls[2],ls[3]); } vVAL tov(Int xl){ dp_.resize(xl,ini); return vVAL(dp_); } vvVAL tov(Int xl,Int yl){ dp_.resize(xl*yl,ini); vvVAL ret(xl,vVAL(yl)); for (ll i=0; i void calcallNormal(const RNG &rng){ STATE vx=rng.start(); do calcSt(vx); while (rng.next(vx)); } template void calcallNextDp(const RNG &rng){ auto [sx,ex,xl,dx]=rng.SELDx(); for (ll xx=0; xx0){ ll id=toID(rng.start(xx-1)); auto it=dp_.begin()+id; fill(it,it+rng.csize(),ini);//dp_[id~id+csize-1]を消去 } //現在位置xxを処理 STATE vx=rng.start(xx); do calcSt(vx); while (rng.next(vx,1)); } } //-------- ダンプ -------- public: #if 0 template void dump(rangeNd &rng,vector labels={},const vector axes={0,1,2,3}){ auto ls=rng.ls(); if (nextdp) ls[0]=rng.cycle(); dumpstring::dumpNd("",tov(ls).tostd(),args().rngs(rng.rngs()).labels(labels).tr(axes)); } #endif //-------- 最適パス -------- #if 0 private: vector pre; ll preini=-1,predmy=-1; ll &Pre(const STATE &vx){ ll id=toID(vx); if ((ll)pre.size()<=id) pre.resize(id+1,preini); return id<0 ? (predmy=preini) : pre[id]; } public: void preRenew(const STATE &vx,const STATE &src){ Pre(vx)=toID(src); } template vector pathget(Args&&... endargs){ vector ids{toID({endargs...})}; while (ids.back()<(ll)pre.size() && pre[ids.back()]!=preini) ids.push_back(pre[ids.back()]); reverse(ids.begin(),ids.end()); vector path; for (auto&& id: ids) path.push_back(fromID(id)); return path; } #else void preRenew(const STATE &vx,const STATE &src)const{ (void)vx,(void)src; } #endif }; template struct mat_: std::vector>{ using P=std::vector>; mat_(){} mat_(initializer_list> a): P(a.begin(),a.end()){ assert(all_of(this->begin(),this->end(),[&](auto &x){return (ll)x.size()==w(); })); } mat_(ll h,ll w,T x=T()): P(h,std::vector(w,x)){} mat_(ll n): P(n,std::vector(n)){} mat_(ll n,const string &c): P(n,std::vector(n)){ if (c=="E")E(); } mat_(std::vector &v,bool istranspose=false){ if (istranspose){ P::resize(1,std::vector((ll)v.size())); for (ll j=0; j(1)); for (ll i=0; i operator*(const std::vector &v) const {//行列*ベクトル std::vector ret(h()); for (ll i=0; i0; i>>=1,a*=a){ if (i&1) ret*=a; } return ret; } mat_ t() const { mat_ ret(w(),h()); for (ll i=0; i; /* mat m={{2,3,4},{1,0,5}}; . ↓2x2正方行列、all0 mat m(2); . ↓2x2 単位行列 mat m(2,"E"); . ↓vectorを縦(n×1)のmat型に変換 mat m(v); . ↓vectorを横(1×n)のmat型に変換 mat m(v,true); . ↓定数倍 m*=mll(2); mat mm=m.pow(i); */ template struct findchar{ using Int = long long; using ll = long long; using S = typename T::value_type; T data; vector> idxss; //idxss[x]: data[i]=xであるiの配列 S offset=0;//vの要素の最小値 findchar(){} findchar(const T& v,S offset_=0){ init(v,offset_); } void init(const T& v,S offset_=0){ data=v; offset=offset_; if (data.empty()) return; auto [mnit,mxit]=minmax_element(v.begin(),v.end()); assert(offset<=*mnit && *mxit &idxs=idxsOf(c); return (Int)idxs.size()<=r ? -1 : idxs[r]; } Int rankOf(Int i)const{ return numOf(data[i],i)-1; } void push_back(S c){ assert(offset<=c); if ((S)idxss.size()<=c-offset) idxss.resize(c-offset+1); idxsOf(c).push_back(size()); data.push_back(c); } void push_back(const T& v){ for (S c : v) push_back(c); } void pop_back(){ if (empty())return; idxsOf(data.back()).pop_back(); data.pop_back(); } private: bool out(S c)const{ return c &idxsOf(S c){ return idxss[c-offset]; } const vector &idxsOf(S c)const{ return idxss[c-offset]; } Int numOf(S c,Int r)const{//区間[0,r]のcの個数 if (out(c))return 0; const vector &idxs=idxsOf(c); return upper_bound(idxs.begin(),idxs.end(),r) - idxs.begin(); } /* 位置i以降d個目の文字c位置 ないとき-1 cycle=trueなら循環 */ Int ceilIdxOfCore(S c,Int i,ll d,bool cycle)const{ if (!contains(c)) return -1; const vector &idxs=idxsOf(c); ll I=ll(lower_bound(idxs.begin(),idxs.end(),i)-idxs.begin()) + d-1; if (cycle) return idxs[I%(ll)idxs.size()]; else return I &idxs=idxsOf(c); ll I=ll(upper_bound(idxs.begin(),idxs.end(),i)-idxs.begin())-1 -(d-1); if (cycle){ ll m=(ll)idxs.size(),Im=I%m; return idxs[Im>=0 ? Im : Im+m]; } else return I>=0 ? idxs[I] : -1; } }; /* - 定義 ↓string,vll等 findchar fc(s); . ↓最小要素指定 findchar fc(s,'a'); findchar fc(v,-100); - 複数定義 vector> vfc(n); vector> vfc(n); for (auto &&e: vfc) e.init("",'a'); //後から初期化 - 使用 ll n=fc.size(); bool b=fc.empty(); fc.clear(); ll nm=fc.numOf(c,l,r); //区間[l,r]の文字cの個数 ll j=fc.idxOf(c,r); //r番目の文字cの位置(0-indexed) ll r=fc.rankOf(i); //位置iはその文字の何番目か(0-indexed) i=0~N-1 bool b=fc.contains(c); //文字cがある ll j=fc.nextIdxOf(i); //位置iと同じ文字の次の位置 なければ-1 i=0~N-1 ll j=fc.prevIdxOf(i); //位置iと同じ文字の前の位置 なければ-1 i=0~N-1 ll j=fc.cycleNextIdxOf(i); //位置iと同じ文字の次の位置(循環) i=0~N-1 ll j=fc.cyclePrevIdxOf(i); //位置iと同じ文字の前の位置(循環) i=0~N-1 ll j=fc.ceilIdxOf(c,i); //位置i以降の文字c位置 なければ-1 ll j=fc.floorIdxOf(c,i); //位置i以前の文字c位置 なければ-1 ll j=fc.cycleCeilIdxOf(c,i); //位置i以降の文字c位置(循環) なければ-1 ll j=fc.cycleFloorIdxOf(c,i); //位置i以前の文字c位置(循環) なければ-1 ll j=fc.nextIdxOf(i,d); //┐ ll j=fc.prevIdxOf(i,d); //│ ll j=fc.cycleNextIdxOf(i,d); //│ ll j=fc.cyclePrevIdxOf(i,d); //├↑の同名関数のd個先/d個前版 d≧1 ll j=fc.ceilIdxOf(c,i,d); //│ ll j=fc.floorIdxOf(c,i,d); //│ ll j=fc.cycleCeilIdxOf(c,i,d); //│ ll j=fc.cycleFloorIdxOf(c,i,d);//┘ fc.push_back(c); //末尾に文字c追加 fc.push_back(s); //string,vll等でまとめて末尾追加 fc.pop_back(); //末尾削除 */ namespace MomentMultiset{ template struct moment{ using MM=moment; T n=0; //要素の個数 S s=0; //要素の和 moment() = default; moment(S x): n(1),s(x){} moment(T n,S s): n(n),s(s){} //--------- 各種演算 -------- [[nodiscard]] MM minkowskiSum(const MM &b)const{ T nx=this->n,ny=b.n; S sx=this->s,sy=b.s; return {nx*ny, ny*sx+nx*sy}; } [[nodiscard]] MM minkowskiProd(const MM &b)const{ return {this->n*b.n, this->s*b.s}; } [[nodiscard]] MM Union(const MM &b)const{ return {this->n+b.n, this->s+b.s}; } //--------- operator 行列累乗時セットする -------- MM operator*(const MM &b)const{ //適切な演算をセット return minkowskiProd(b); //return minkowskiSum(b); } MM operator+(const MM &b)const{ //適切な演算をセット return Union(b); } MM &operator*=(const MM &b){ return *this=(*this)*b; } MM &operator+=(const MM &b){ return *this=(*this)+b; } auto operator<=>(const MM& b) const = default; //辞書順比較を自動生成 #if 0 //デバグ時ON string to_string()const{ return stringfx(n)+","+stringfx(s); } #endif }; template struct moment2{ using MM=moment2; T n=0; //要素の個数 S s=0; //要素の和 R s2=0;//要素の2乗和 moment2() = default; moment2(S x): n(1),s(x),s2(x*x) {} moment2(T n,S s,R s2): n(n),s(s),s2(s2) {} //--------- 各種演算 -------- [[nodiscard]] MM minkowskiSum(const MM &b)const{ T nx= this->n,ny =b.n; S sx= this->s,sy =b.s; R sx2=this->s2,sy2=b.s2; return {nx*ny, ny*sx+nx*sy, ny*sx2 + 2*sx*sy + nx*sy2}; } [[nodiscard]] MM minkowskiProd(const MM &b)const{ return {this->n*b.n, this->s*b.s, this->s2*b.s2}; } [[nodiscard]] MM Union(const MM &b)const{ return {this->n+b.n, this->s+b.s, this->s2+b.s2}; } //--------- operator 行列累乗時セットする -------- MM operator*(const MM &b)const{ //適切な演算をセット return minkowskiProd(b); //return minkowskiSum(b); } MM operator+(const MM &b)const{ //適切な演算をセット return Union(b); } MM &operator*=(const MM &b){ return *this=(*this)*b; } MM &operator+=(const MM &b){ return *this=(*this)+b; } auto operator<=>(const MM& b) const = default; //辞書順比較を自動生成 #if 0 //デバグ時ON string to_string()const{ return stringfx(n)+","+stringfx(s)+","+stringfx(s2); } #endif }; } using MomentMultiset::moment; using MomentMultiset::moment2; /* DPで、条件を満たす要素の多重集合の個数・和・2乗和を求めたいとき、 valueに本クラスを使う。 - ---- 型定義 ---- using mom = moment ; //個数・和 using mom = moment2; //個数・和・2乗和 - ---- 定義 ---- mom m; //空集合のmoment(単位元) mom m(x); //{x}(要素がx一つの集合)のmoment mom m(n,s,s2);//要素数n,和s,2乗和s2のmoment - ---- アクセス ---- ll n=m.n; //個数n ll s=m.s; //和s ll s2=m.s2; //2乗和s2 - ---- 演算 ---- mom mZ=mX.minkowskiSum(mom(c)); //多重集合Xの全要素に+c mom mZ=mX.minkowskiProd(mom(k)); //多重集合Xの全要素をk倍 mom mZ=mX.Union(mY); //┬直和X+Y (X={1,3},Y={1,4}ならX+Y={1,1,3,4}) mom mZ=mX+mY; //┘ mom mZ=mX.minkowskiSum(mY); //ミンコフスキー和 Z=X⊕Y={x+y|x∈X,y∈Y} mom mZ=mX.minkowskiProd(mY); //ミンコフスキー積 Z=X⊗Y={x*y|x∈X,y∈Y} mom mZ=mX*mY; //default:ミンコフスキー積、適宜変更する - ---- operator *,+,*=,+= ---- 行列累乗にしたいときは+と*を適切に定める。 */ using mom = moment ; //個数・和 using vmom=vector; template T sumPowers(T a,T e,long long n){ T ret=e; T b=e; //e+x+x^2+…+x^(2ベキ) for (;n>0;n>>=1,b=b*a+b,a*=a){ if (n&1) ret=ret*a+b; } return ret; } /* mll x=sumPowers(a,1,n); //1+a+a^2+…+a^n mat B=sumPowers(A,E,n); //E+A+A^2+…+A^n . ↑単位元 */ void cin2solve() { auto S=cin1(); ll N=sz(S); auto K=cin1(); findchar fc(S); ll G=10; ll D=20; auto dpcalc=[&](ll st,ll cs/*0:個数、1:和*/){ //数字stの個数/和 の寄与を計算 //戻り //ret:{c0,s0,c1,s1,…,c9,s9} //sm :「N内で終わるものの和」への寄与 dp(*).s を全部足す using STATE=array; using VAL=mom; auto operation=[&](VAL a,VAL b){return a+b; }; VAL ini=mom(); bool isinf=false; vmom ret(G); auto transition=[&](const STATE &vx,VAL va,auto dstVal){ const auto [i]=vx; rep(dg,0,9){ if (i==-1 and dg!=st)continue; //i+1以降でdgが初めに出てくる位置 j ll j=fc.ceilIdxOf(char('0'+dg),i+1);//位置i以降の文字c位置 なければ-1 if (j==-1) ret[dg]+=va; else{ mom vaZ=va .minkowskiProd(mom(10)); //多重集合Xの全要素をk倍 mom vaY=vaZ.minkowskiSum(mom(dg)); //多重集合Xの全要素に+c dstVal(STATE{j},vaY); } } }; auto [s1,e1]=pll{-1,N-1}; //1つ目の変数の範囲 rangeNd<1> rng({s1,},{e1,}); PushBasedDP dp(STATE(),VAL(),operation,transition,rng.toID(),rng.fromID(),ini,isinf,rng); if (cs==0) dp(-1)=mom(1,0); else dp(-1)=mom(0,1); dp.calcall(rng); mll sm; rep(i,0,N-1) sm+=dp(i).s; vmll retv(D); rep(i,0,9){ retv[2*i+0]=ret[i].n; retv[2*i+1]=ret[i].s; } return make_pair(retv,sm); }; mat A(D); vmll u(D); rep(st,0,9){ { auto [retv,sm]=dpcalc(st,0); rep(i,0,D-1) A[i][2*st+0]=retv[i]; u[2*st+0]=sm; } { auto [retv,sm]=dpcalc(st,1); rep(i,0,D-1) A[i][2*st+1]=retv[i]; u[2*st+1]=sm; } } vmll v{0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,}; mat B=sumPowers(A,mat(D,"E"),K-1); vmll v2=B*v; mat U(u,true); mll ans=(U*v2)[0]; cout << ans << '\n'; return; } }//SolvingSpace ////////////////////////////////////////// int main(){ #if defined(RANDOM_TEST) //SolvingSpace::cin2solve(); SolvingSpace::generand(); #else #if 1 //SolvingSpace::labo();' SolvingSpace::cin2solve(); #else ll t; cin >> t; rep(i,0,t-1){ SolvingSpace::cin2solve(); } #endif #endif cerr << timeget() <<"ms"<< '\n'; return 0; }