QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#73170#4384. WalkpoiAC ✓1219ms460652kbC++5.1kb2023-01-22 17:31:222023-01-22 17:31:25

Judging History

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

  • [2023-08-10 23:21:45]
  • System Update: QOJ starts to keep a history of the judgings of all the submissions.
  • [2023-01-22 17:31:25]
  • 评测
  • 测评结果:AC
  • 用时:1219ms
  • 内存:460652kb
  • [2023-01-22 17:31:22]
  • 提交

answer

#include "iostream"
#include "cstring"
#include "cstdio"
#include "algorithm"
#include "queue"
#include "vector"
#include "queue"
#include "stack"
#include "ctime"
#include "set"
#include "map"
#include "cmath"
using namespace std;
#define fi first
#define se second
#define vi vector<int>
#define pb push_back
#define eb emplace_back
#define pii pair<int,int>
#define mp make_pair
#define rep( i , a , b ) for( int i = (a) , i##end = b ; i <= i##end ; ++ i )
#define per( i , a , b ) for( int i = (a) , i##end = b ; i >= i##end ; -- i )
#define mem( a ) memset( a , 0 , sizeof (a) )
#define all( x ) x.begin() , x.end()
//#define int long long
typedef long long ll;
const int MAXN = 2e6 + 10;
const int P = 998244353;
int n , m;
int v[MAXN];

int Pow( int x , int a ) {
	int ret = 1;
	while( a ) {
		if( a & 1 ) ret = ret * 1ll * x % P;
		x = x * 1ll * x % P , a >>= 1;
	}
	return ret;
}

int Wn[2][MAXN];
void getwn( int len ) {
	for( int mid = 1 ; mid < len ; mid <<= 1 ) {
		int w0 = Pow( 3 , ( P - 1 ) / ( mid << 1 ) ) , w1 = Pow( 3 , P - 1 - ( P - 1 ) / ( mid << 1 ) );
		Wn[0][mid] = Wn[1][mid] = 1;
		for( int i = 1 ; i < mid ; ++ i )
			Wn[0][mid + i] = Wn[0][mid + i - 1] * 1ll * w0 % P,
			Wn[1][mid + i] = Wn[1][mid + i - 1] * 1ll * w1 % P;
	}
}
int rev[MAXN];
void getr( int len ) {
	int l = __builtin_ctz( len ) - 1;
	for( int i = 1 ; i < len ; ++ i ) rev[i] = ( rev[i >> 1] >> 1 ) | ( ( i & 1 ) << l );
}
void NTT( vi& A , int len , int typ ) {
	for( int i = 0 ; i < len ; ++ i ) if( i < rev[i] ) swap( A[i] , A[rev[i]] );
	for( int mid = 1 ; mid < len ; mid <<= 1 )
		for( int i = 0 ; i < len ; i += ( mid << 1 ) )
			for( int j = i ; j < i + mid ; ++ j ) {
				int t0 = A[j] , t1 = A[j + mid] * 1ll * Wn[typ][j - i + mid] % P;
				A[j] = ( t0 + t1 > P ? t0 + t1 - P : t0 + t1 ) , A[j + mid] = ( t0 < t1 ? t0 - t1 + P : t0 - t1 );
			}
	if( typ ) for( int i = 0 , iv = Pow( len , P - 2 ) ; i < len ; ++ i ) A[i] = A[i] * 1ll * iv % P;
}
void NTT( int A[] , int len , int typ ) {
	for( int i = 0 ; i < len ; ++ i ) if( i < rev[i] ) swap( A[i] , A[rev[i]] );
	for( int mid = 1 ; mid < len ; mid <<= 1 )
		for( int i = 0 ; i < len ; i += ( mid << 1 ) )
			for( int j = i ; j < i + mid ; ++ j ) {
				int t0 = A[j] , t1 = A[j + mid] * 1ll * Wn[typ][j - i + mid] % P;
				A[j] = ( t0 + t1 > P ? t0 + t1 - P : t0 + t1 ) , A[j + mid] = ( t0 < t1 ? t0 - t1 + P : t0 - t1 );
			}
	if( typ ) for( int i = 0 , iv = Pow( len , P - 2 ) ; i < len ; ++ i ) A[i] = A[i] * 1ll * iv % P;
}
vi mul( vi A , vi B , int flg = 0 ) {
	if( A.empty() || B.empty() ) return vector<int> ();
	int S = A.size() + B.size() , len = 1;
	while( len <= S ) len <<= 1;
	getr( len );
	A.resize( len ) , B.resize( len );
	NTT( A , len , 0 ) , NTT( B , len , 0 );
	rep( i , 0 , len - 1 ) A[i] = A[i] * 1ll * B[i] % P;
	NTT( A , len , 1 );
	while( A.size() && A.back() == 0 ) A.pop_back();
	return A;
}

//template<typename T>
//T&& add( T&& A , T&& B ) {
//	if( A.size() > B.size() ) {
//		rep( i , 0 , B.size() - 1 ) A[i] += B[i];
//		return forward<T>( A );
//	} else {
//		rep( i , 0 , A.size() - 1 ) B[i] += A[i];
//		return forward<T>( B ); 
//	}
//}

vi add( vi A , vi B ) {
	if( A.size() > B.size() ) {
		rep( i , 0 , B.size() - 1 ) A[i] = ( A[i] + B[i] ) % P;
		return A;
	} else {
		rep( i , 0 , A.size() - 1 ) B[i] = ( B[i] + A[i] ) % P;
		return B;
	}
}

const int N = 3;
struct mtrx {
	vi A[3][3];
	mtrx operator * ( mtrx B ) {
		mtrx res;
		rep( i , 0 , N - 1 ) rep( j , 0 , N - 1 ) rep( k , 0 , N - 1 ) 
			res.A[i][j] = add( res.A[i][j] , mul( A[i][k] , B.A[k][j] ) );
		return res;
	}
	void init( int i ) {
		if( i <= 16 ) {
			A[0][0] = { 1 , P - v[i] };
			A[1][0] = { 1 };
			A[2][1] = { 1 };
		} else if( i <= 65537 ) {
			A[0][0] = { 1 } , A[0][1] = { 0 , P - v[i] };
			A[1][0] = { 1 };
			A[2][1] = { 1 };
		} else {
			A[0][0] = { 1 } , A[0][2] = { 0 , P - v[i] };
			A[1][0] = { 1 } , A[2][1] = { 1 };
		}
	}
} A[MAXN] ;

mtrx mul( int l , int r ) {
	if( l == r ) 
		return A[l];
	int m = ( l + r >> 1 );
//	mtrx&& ret = mul( l , m ) * mul( m + 1 , r );
// 	if( r - l > 300 ) cout << ret.A[0][0].size() << endl;
	return mul( m + 1 , r ) * mul( l , m );
}

int tmpa[MAXN];
void Inv( vi A , int B[] , int n ) { // B = inv A
	if( n == 1 ) return void( B[0] = Pow( A[0] , P - 2 ) );
	Inv( A , B , n + 1 >> 1 );
	int len = 1;
	while( len <= n + n ) len <<= 1;
	getr( len );
	for( int i = 0 ; i < n ; ++ i ) tmpa[i] = A[i];
	for( int i = n ; i < len ; ++ i ) tmpa[i] = 0;
	NTT( tmpa , len , 0 ) , NTT( B , len , 0 );
	rep( i , 0 , len - 1 ) B[i] = B[i] * ( 2 - tmpa[i] * 1ll * B[i] % P + P ) % P;
	NTT( B , len , 1 );
	rep( i , n , len - 1 ) B[i] = 0;
}

int as[MAXN];

void solve() {
	cin >> n >> m;
	rep( i , 1 , m ) scanf("%d",v + i) , A[i].init( i );
	mtrx pr;
	pr.A[0][0] = { 1 };
	mtrx res = mul( 1 , m );
	vi re = res.A[0][0];
//	for( int x : re ) cout << x << endl;
	re.resize( n + 1 );
	Inv( re , as , n + 1 );
	cout << as[n] << endl;
}

signed main() {
	getwn( 1 << 19 );
//	freopen("in","r",stdin);
//	freopen("out","w",stdout);
//	int T;cin >> T;while( T-- ) solve();
	solve();
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1219ms
memory: 460652kb

input:

99990 99987
757148 167851001 301413357 336971125 659598369 160567226 391749388 4890852 35766291 26239573 473038165 597007 3615545 326051437 392289611 118341523 170427799 37215529 675016434 168544291 683447134 950090227 82426873 116752252 194041605 706221269 71664782 257655784 84970744 21417563 37379...

output:

748098408

result:

ok single line: '748098408'