QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#679284#9526. Subsequence Countingucup-team159#TL 1ms3724kbC++2310.9kb2024-10-26 17:17:212024-10-26 17:17:21

Judging History

你现在查看的是最新测评结果

  • [2024-10-26 17:17:21]
  • 评测
  • 测评结果:TL
  • 用时:1ms
  • 内存:3724kb
  • [2024-10-26 17:17:21]
  • 提交

answer

#line 1 "H.cpp"
// #pragma GCC target("avx2,avx512f,avx512vl,avx512bw,avx512dq,avx512cd,avx512vbmi,avx512vbmi2,avx512vpopcntdq,avx512bitalg,bmi,bmi2,lzcnt,popcnt")
// #pragma GCC optimize("Ofast")

#line 2 "/home/sigma/comp/library/template.hpp"

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using uint = unsigned int;
using ull = unsigned long long;
#define rep(i,n) for(int i=0;i<int(n);i++)
#define rep1(i,n) for(int i=1;i<=int(n);i++)
#define per(i,n) for(int i=int(n)-1;i>=0;i--)
#define per1(i,n) for(int i=int(n);i>0;i--)
#define all(c) c.begin(),c.end()
#define si(x) int(x.size())
#define pb push_back
#define eb emplace_back
#define fs first
#define sc second
template<class T> using V = vector<T>;
template<class T> using VV = vector<vector<T>>;
template<class T,class U> bool chmax(T& x, U y){
	if(x<y){ x=y; return true; }
	return false;
}
template<class T,class U> bool chmin(T& x, U y){
	if(y<x){ x=y; return true; }
	return false;
}
template<class T> void mkuni(V<T>& v){sort(all(v));v.erase(unique(all(v)),v.end());}
template<class T> int lwb(const V<T>& v, const T& a){return lower_bound(all(v),a) - v.begin();}
template<class T>
V<T> Vec(size_t a) {
    return V<T>(a);
}
template<class T, class... Ts>
auto Vec(size_t a, Ts... ts) {
  return V<decltype(Vec<T>(ts...))>(a, Vec<T>(ts...));
}
template<class S,class T> ostream& operator<<(ostream& o,const pair<S,T> &p){
	return o<<"("<<p.fs<<","<<p.sc<<")";
}
template<class T> ostream& operator<<(ostream& o,const vector<T> &vc){
	o<<"{";
	for(const T& v:vc) o<<v<<",";
	o<<"}";
	return o;
}
constexpr ll TEN(int n) { return (n == 0) ? 1 : 10 * TEN(n-1); }

#ifdef LOCAL
#define show(x) cerr << "LINE" << __LINE__ << " : " << #x << " = " << (x) << endl
void dmpr(ostream& os){os<<endl;}
template<class T,class... Args>
void dmpr(ostream&os,const T&t,const Args&... args){
	os<<t<<" ~ ";
	dmpr(os,args...);
}
#define shows(...) cerr << "LINE" << __LINE__ << " : ";dmpr(cerr,##__VA_ARGS__)
#define dump(x) cerr << "LINE" << __LINE__ << " : " << #x << " = {";  \
	for(auto v: x) cerr << v << ","; cerr << "}" << endl;
#else
#define show(x) void(0)
#define dump(x) void(0)
#define shows(...) void(0)
#endif

template<class D> D divFloor(D a, D b){
	return a / b - (((a ^ b) < 0 && a % b != 0) ? 1 : 0);
}
template<class D> D divCeil(D a, D b) {
	return a / b + (((a ^ b) > 0 && a % b != 0) ? 1 : 0);
}
#line 1 "/home/sigma/comp/library/math/mint.cpp"
/*
	任意mod なら 
	template なくして costexpr の行消して global に unsigned int mod = 1;
	で cin>>mod してから使う
	任意 mod はかなり遅いので、できれば "atcoder/modint" を使う
*/

template<unsigned int mod_>
struct ModInt{	
	using uint = unsigned int;
	using ll = long long;
	using ull = unsigned long long;

	constexpr static uint mod = mod_;

	uint v;
	ModInt():v(0){}
	ModInt(ll _v):v(normS(_v%mod+mod)){}
	explicit operator bool() const {return v!=0;}
	static uint normS(const uint &x){return (x<mod)?x:x-mod;}		// [0 , 2*mod-1] -> [0 , mod-1]
	static ModInt make(const uint &x){ModInt m; m.v=x; return m;}
	ModInt operator+(const ModInt& b) const { return make(normS(v+b.v));}
	ModInt operator-(const ModInt& b) const { return make(normS(v+mod-b.v));}
	ModInt operator-() const { return make(normS(mod-v)); }
	ModInt operator*(const ModInt& b) const { return make((ull)v*b.v%mod);}
	ModInt operator/(const ModInt& b) const { return *this*b.inv();}
	ModInt& operator+=(const ModInt& b){ return *this=*this+b;}
	ModInt& operator-=(const ModInt& b){ return *this=*this-b;}
	ModInt& operator*=(const ModInt& b){ return *this=*this*b;}
	ModInt& operator/=(const ModInt& b){ return *this=*this/b;}
	ModInt& operator++(int){ return *this=*this+1;}
	ModInt& operator--(int){ return *this=*this-1;}
	template<class T> friend ModInt operator+(T a, const ModInt& b){ return (ModInt(a) += b);}
	template<class T> friend ModInt operator-(T a, const ModInt& b){ return (ModInt(a) -= b);}
	template<class T> friend ModInt operator*(T a, const ModInt& b){ return (ModInt(a) *= b);}
	template<class T> friend ModInt operator/(T a, const ModInt& b){ return (ModInt(a) /= b);}
	ModInt pow(ll p) const {
		if(p<0) return inv().pow(-p);
		ModInt a = 1;
		ModInt x = *this;
		while(p){
			if(p&1) a *= x;
			x *= x;
			p >>= 1;
		}
		return a;
	}
	ModInt inv() const {		// should be prime
		return pow(mod-2);
	}
	// ll extgcd(ll a,ll b,ll &x,ll &y) const{
	// 	ll p[]={a,1,0},q[]={b,0,1};
	// 	while(*q){
	// 		ll t=*p/ *q;
	// 		rep(i,3) swap(p[i]-=t*q[i],q[i]);
	// 	}
	// 	if(p[0]<0) rep(i,3) p[i]=-p[i];
	// 	x=p[1],y=p[2];
	// 	return p[0];
	// }
	// ModInt inv() const {
	// 	ll x,y;
	// 	extgcd(v,mod,x,y);
	// 	return make(normS(x+mod));
	// }

	bool operator==(const ModInt& b) const { return v==b.v;}
	bool operator!=(const ModInt& b) const { return v!=b.v;}
	bool operator<(const ModInt& b) const { return v<b.v;}
	friend istream& operator>>(istream &o,ModInt& x){
		ll tmp;
		o>>tmp;
		x=ModInt(tmp);
		return o;
	}
	friend ostream& operator<<(ostream &o,const ModInt& x){ return o<<x.v;}
	// friend ostream& operator<<(ostream &o,const ModInt& x){
	// 	for(int b=1;b<=1000;b++){
	// 		ModInt ib = ModInt(b).inv();
	// 		for(int a=-1000;a<=1000;a++){
	// 			if(ModInt(a) * ib == x){
	// 				return o << a << "/" << b;
	// 			}
	// 		}
	// 	}
	// 	return o<<x.v;
	// }
};
using mint = ModInt<998244353>;
//using mint = ModInt<1000000007>;

V<mint> fact,ifact,invs;
// a,b >= 0 のみ
mint Choose(int a,int b){
	if(b<0 || a<b) return 0;
	return fact[a] * ifact[b] * ifact[a-b];
}

/*
// b >= 0 の範囲で、 Choose(a,b) = a(a-1)..(a-b+1) / b!
mint Choose(int a,int b){
	if(b<0 || a<b) return 0;
	return fact[a] * ifact[b] * ifact[a-b];
}
*/

void InitFact(int N){	//[0,N]
	N++;
	fact.resize(N);
	ifact.resize(N);
	invs.resize(N);
	fact[0] = 1;
	rep1(i,N-1) fact[i] = fact[i-1] * i;
	ifact[N-1] = fact[N-1].inv();
	for(int i=N-2;i>=0;i--) ifact[i] = ifact[i+1] * (i+1);
	rep1(i,N-1) invs[i] = fact[i-1] * ifact[i];
}
#line 6 "H.cpp"

template<class D>
struct Segtree{
	int N;
	vector<D> val;

	Segtree(){}
	Segtree(int n){
		N = 1; while(N < n) N *= 2;
		val.assign(N*2, D());
	}
	template<class Dlike>
	Segtree(const vector<Dlike>& vs){
		int n = vs.size();
		N = 1; while(N < n) N *= 2;
		val.assign(N*2, D());
		rep(i,n) val[i+N] = vs[i];
		for(int i=N-1;i>0;i--) val[i] = D::op(val[i*2],val[i*2+1]);
	}
	void set(int k, D v){
		k += N;
		val[k] = v;
		k /= 2;
		while(k){
			val[k] = D::op(val[k*2],val[k*2+1]);
			k /= 2;
		}
	}
	void add(int k, D v){
		k += N;
		val[k] = D::op(val[k],v);
		k /= 2;
		while(k){
			val[k] = D::op(val[k*2],val[k*2+1]);
			k /= 2;
		}
	}
	D query(int a, int b){		//non-commutative & unrecursive
		D L = D() , R = D();
		a += N, b += N;
		while(a<b){
			if(a&1) L = D::op(L,val[a++]);
			if(b&1) R = D::op(val[--b],R);
			a /= 2, b /= 2;
		}
		return D::op(L,R);
	}
};

struct EG { ll g, x, y; };
EG extGcdSub(ll a, ll b) {
	if(b == 0){
		if (a >= 0) return EG{a, 1, 0};
		else return EG{-a, -1, 0};
	}else{
		auto e = extGcdSub(b, a % b);
		return EG{e.g, e.y, e.x - a / b * e.y};
	}
}
EG extGcd(ll a,ll b){
	auto e = extGcdSub(a,b);
	if(e.x < 0){
		if(b > 0){
			e.x += b/e.g;
			e.y -= a/e.g;
		}else{
			e.x -= b/e.g;
			e.y += a/e.g;
		}
	}
	return e;
}
/*
	xz + md? = g
*/
ll inv_mod(ll x, ll md) {
	auto z = extGcd(x, md).x;
	return (z % md + md) % md;
}

// struct Monoid{
// 	string s;
// 	Monoid():s(""){}
// 	Monoid(string s_):s(s_){}

// 	static Monoid op(const Monoid &a, const Monoid &b){
// 		return Monoid{a.s+b.s};
// 	}
// 	Monoid pow(ll p) const {
// 		Monoid a = Monoid();
// 		Monoid x = *this;
// 		while(p){
// 			if(p&1) a = op(a, x);
// 			x = op(x, x);
// 			p >>= 1;
// 		}
// 		return a;
// 	}
// 	friend ostream& operator<<(ostream &o,const Monoid& x){ return o<<x.s;}
// };

// array<array<T,11>,11>
template<class T>
struct Matrix: public array<array<T,11>,11>{

	Matrix(int h,int w){
		rep(i,h) rep(j,w) (*this)[i][j] = 0;
	}
	Matrix(const array<array<T,11>,11>& m){(*this) = m;}

	static Matrix E(int n){
		Matrix a(n,n);
		rep(i,n) a[i][i] = 1;
		return a;
	}
	int h() const { return (*this).size(); }
	int w() const { return (*this)[0].size(); }

	Matrix operator*(const Matrix& r) const {
		assert(w() == r.h());
		int A = h(), B = w(), C = r.w();
		Matrix z(A,C);
		rep(i,A) rep(k,B) rep(j,C) z[i][j] += (*this)[i][k] * r[k][j];
		return z;
	}
	Matrix& operator+=(const Matrix& r){return (*this)=(*this)+r;}
	Matrix& operator-=(const Matrix& r){return (*this)=(*this)-r;}
	Matrix& operator*=(const Matrix& r){return (*this)=(*this)*r;}

	Matrix pow(ll p) const {
		assert(h() == w());
		Matrix res = E(h());
		Matrix x = *this;
		while(p){
			if(p&1) res *= x;
			x *= x;
			p >>= 1;
		}
		return res;
	}

	friend ostream& operator<<(ostream &o,const Matrix& A){
		rep(i,A.h()){
			rep(j,A.w()) o << A[i][j]<<" ";
			o << endl;
		}
		return o;
	}
};
using Mat = Matrix<mint>;

int M;

struct Monoid{
	Mat m;
	Monoid():m(Mat::E(M+1)){}
	Monoid(Mat m_):m(m_){}

	static Monoid op(const Monoid &a, const Monoid &b){
		return Monoid{a.m*b.m};
	}
	Monoid pow(ll p) const {
		return Monoid{m.pow(p)};
	}
	friend ostream& operator<<(ostream &o,const Monoid& x){ return o<<x.m;}
};


template<class T>
T f(V<ll> xs, V<T> vs, ll K){
	show("-------------");
	show(xs); show(vs); show(K);

	int N = si(vs);
	assert(si(xs) == N + 1);
	assert(xs[0] == 0);

	if(N == 1) return vs[0].pow(xs[1]);

	ll L = xs[N];
	V<ll> cands;
	for(ll x: xs) cands.pb(x%K);
	mkuni(cands);
	V<ll> nxs;
	V<T> nvs;
	vector<ll> buf(N, -1);
	Segtree<T> seg(N);
	for(ll r: cands){
		nxs.pb(r);
		rep(i,N){
			// [xs[i], xs[i+1]) にある qK + r の個数
			ll num = divFloor(xs[i+1]-r-1, K) - divFloor(xs[i]-r-1, K);
			if(num != buf[i]){
				buf[i] = num;
				seg.set(i, vs[i].pow(num));
			}
		}
		auto nv = seg.query(0, N);
		nvs.pb(nv);
	}
	nxs.pb(K);
	ll nK = L/K*K+K - L;
	return f(nxs, nvs, nK);
}

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);		//DON'T USE scanf/printf/puts !!
	cout << fixed << setprecision(20);

	// {
	// 	string s = string(10,'a') + string(6,'b') + string(10,'a') + string(1,'b');
	// 	string t;
	// 	rep(i,27) t += s[i*17%27];
	// 	int res = 0;
	// 	rep(i,27) for(int j = i+1;j<27;j++) if(t[i] == 'a' && t[j] == 'b') res++;
	// 	cout << res << endl;
	// 	return 0;
	// }

	int N; ll K,L; cin >> N >> M >> K >> L;
	K = inv_mod(K, L);

	V<int> t(M); rep(i,M) cin >> t[i];

	V<ll> xs;
	V<Monoid> vs;
	int sm = 0;
	xs.pb(sm);
	rep(i,N){
		int len, val; cin >> len >> val;
		sm += len;
		xs.pb(sm);
		Mat m(M+1,M+1); rep(j,M+1) m[j][j] = 1;
		rep(j,M) if(t[j] == val) m[j][j+1] = 1;
		vs.pb(Monoid(m));
	}
	Monoid res = f(xs, vs, K);
	cout << res.m[0][M] << endl;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1ms
memory: 3648kb

input:

4 2 17 27
3 1
10 3
6 1
10 3
1 1

output:

76

result:

ok single line: '76'

Test #2:

score: 0
Accepted
time: 1ms
memory: 3724kb

input:

5 3 1789 15150
555 718 726
72 555
1029 718
5807 726
1002 718
7240 555

output:

390415327

result:

ok single line: '390415327'

Test #3:

score: 0
Accepted
time: 0ms
memory: 3604kb

input:

1 1 1 1000000000
1000
1000000000 1000

output:

1755647

result:

ok single line: '1755647'

Test #4:

score: -100
Time Limit Exceeded

input:

1999 10 999999999 1000000000
944 901 986 915 979 988 947 999 969 946
198832 985
235662 982
367137 938
219700 949
166086 906
488084 905
891250 984
243743 971
253382 987
181971 935
2382 948
462701 981
4681 925
113363 916
119397 921
337742 982
427128 921
285959 986
197975 978
140753 907
167150 974
4576...

output:


result: