题解 小L的数列

传送门

重度卡常题,还不给O2

发现看着很像矩阵优化,所以试着放到矩阵上
发现乘法可以转化为每个底数的幂次的加法,于是可以转移了
具体地,考虑矩阵乘法的实际意义,可以用初始矩阵的一列来描述一个 \(f_i\)
然后转移就很好写了,\(b_{k, j}\) 的实际意义就是一列要乘的系数
复杂度 \(O(k^3logn)\),会被卡成50pts
若是每次转移 \(k\) 轮而不是1轮就可以到 \(O(k^3log\frac{n}{k})\),就可以过了

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k;
ll b[N], f[N];
const ll mod=998244353;
const ll mod2=mod-1;
const int imod2=mod2;
inline void md2(int& a, int b) {a+=b; a=a>=imod2?a-imod2:a;}
inline ll qpow(ll a, ll b) {ll ans=1ll; for (; b; b>>=1,a=a*a%mod) if (b&1) ans=ans*a%mod; return ans;}

namespace force{
	void solve() {
		for (int i=k+1; i<=n; ++i) {
			f[i]=1;
			for (int j=1; j<=k; ++j) {
				f[i]=f[i]*qpow(f[i-j], b[j])%mod;
			}
		}
		printf("%lld\n", f[n]);
		exit(0);
	}
}

namespace task1{
	struct matrix{
		int a[205][205], n, m;
		matrix(){memset(a, 0, sizeof(a));}
		matrix(int x, int y){n=x; m=y; memset(a, 0, sizeof(a));}
		inline void resize(int x, int y){n=x; m=y; memset(a, 0, sizeof(a));}
		void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]<<' '; cout<<endl;} cout<<endl;}
		inline int* operator [] (int t) {return a[t];}
		inline matrix operator * (matrix b) {
			matrix ans(n, b.m);
			for (int i=1; i<=n; ++i)
				for (int k=1; k<=m; ++k) if (a[i][k])
					for (int j=1; j<=b.m; ++j)
						md2(ans[i][j], 1ll*a[i][k]*b[k][j]%mod2);
			return ans;
		}
	}mat, t;
	matrix qpow(matrix a, ll b) {matrix ans=a; --b; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}
	inline ll qpow(ll a, ll b) {ll ans=1ll; for (; b; b>>=1,a=a*a%mod) if (b&1) ans=ans*a%mod; return ans;}
	void solve() {
		if (n<=k) {printf("%lld\n", f[n]); exit(0);}
		mat.resize(k, k); t.resize(k, k);
		for (int i=1; i<=k; ++i) mat[i][i]=1;
		for (int i=2; i<=k; ++i) t[i][i-1]=1;
		for (int i=1; i<=k; ++i) t[i][k]=b[k-i+1];
		
		#if 0
		cout<<"---mat---"<<endl;
		mat.put();
		cout<<"---t---"<<endl;
		t.put();
		mat=mat*t;
		cout<<"---ans---"<<endl;
		mat.put();
		#endif

		t=qpow(t, n-k);
		// cout<<"---t---"<<endl;
		// t.put();
		mat=mat*t;
		ll ans=1;
		// cout<<"---ans---"<<endl;
		// mat.put();
		for (int i=1; i<=k; ++i) ans=ans*qpow(f[i], mat[i][k])%mod;
		printf("%lld\n", ans);
		exit(0);
	}
}

signed main()
{
	freopen("seq.in", "r", stdin);
	freopen("seq.out", "w", stdout);

	n=read(); k=read();
	bool all_one=1;
	for (int i=1; i<=k; ++i) b[i]=read();
	for (int i=1; i<=k; ++i) {
		f[i]=read();
		if (f[i]!=1) all_one=0;
	}
	// force::solve();
	if (all_one) {puts("1"); return 0;}
	else task1::solve();

	return 0;
}
posted @ 2021-10-10 15:13  Administrator-09  阅读(2)  评论(0编辑  收藏  举报