题解 相似序列问题 / B关系

相似序列问题
B关系

将限制转化为 LCS 长度 \(\geqslant n-2\)
根据转移 \(f_{i, j}=\max(f_{i-1, j}, f_{i, j-1}, f_{i-1, j-1}[s_i=t_j])\) 得到只有两维之差 \(\leqslant 2\) 的状态是有用的
那么 dp 套 dp,考虑两维中较大的一个到了 \(i\),dp 状态为 \(s\) 的方案数
\(s\) 记录 \(i, j\) 可以记 \(i-f_{i, j}\),还需要记录 \(s_i, s_{i-1}, t_j, t_{j-1}\) 的相等关系,用最小表示法记会很方便
可以搜出状态数只有 120 多种,那么对所有状态矩乘的复杂度是可以接受的 \(O(123^3\log n)\)
然后前面部分是常数所以复杂度 \(O(\log n)\)(逃

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define pb push_back
#define ll long long
#define ull unsigned long long
//#define ll 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, m;
const ll mod=1e9+7;

namespace force{
	ll ans;
	#define inf 3
	vector<int> tem;
	const ull base=13131;
	vector<vector<int>> sta;
	unordered_map<ull, bool> mp;
	void dfs(int u) {
		if (u>n) {
			sta.pb(tem);
			return ;
		}
		for (int i=1; i<=m; ++i) tem[u]=i, dfs(u+1);
	}
	void solve() {
		tem.resize(n+1);
		dfs(1);
		for (int i=0; i<sta.size(); ++i) {
			mp.clear();
			for (int x=1; x<=n; ++x) {
				for (int y=x+1; y<=n; ++y) {
					ull tem=0;
					for (int z=1; z<=n; ++z) if (z!=x&&z!=y) tem=tem*base+sta[i][z];
					mp[tem]=1;
				}
			}
			for (int j=0; j<sta.size(); ++j) {
				for (int x=1; x<=n; ++x) {
					for (int y=x+1; y<=n; ++y) {
						ull tem=0;
						for (int z=1; z<=n; ++z) if (z!=x&&z!=y) tem=tem*base+sta[j][z];
						if (mp.find(tem)!=mp.end()) {++ans; goto jump;}
					}
				}
				jump: ;
			}
		}
		cout<<ans<<endl;
	}
}

namespace task{
	ll dat[N], ans;
	int uni[N], top;
	struct dp{
		ll val[3][3], exp[5];
		dp(){memset(val, 0, sizeof(val)); memset(exp, 0, sizeof(exp));}
		dp(ll a, ll b, ll c, ll d){memset(val, 0, sizeof(val)); exp[1]=a; exp[2]=b; exp[3]=c; exp[4]=d;}
		inline ll* operator [] (int t) {return val[t];}
		inline void put() {
			for (int i=0; i<3; ++i) {for (int j=0; j<3; ++j) cout<<val[i][j]<<' '; cout<<endl;}
			for (int i=1; i<=4; ++i) cout<<exp[i]<<' '; cout<<endl<<endl;
		}
		void flush() {
			int usiz=0;
			for (int i=1; i<8; ++i) uni[i]=0;
			for (int i=1; i<=4; ++i) {
				if (!uni[exp[i]]) uni[exp[i]]=++usiz;
				exp[i]=uni[exp[i]];
			}
		}
		dp calc(int x, int y) {
			dp ans(exp[3], exp[4], x, y);
			ans.flush();
			ans[2][0]=min(val[1][0]+1, exp[1]==y?val[2][0]:inf);
			ans[0][2]=min(val[0][1]+1, x==exp[2]?val[0][2]:inf);
			ans[1][0]=min({val[0][0]+1, ans[2][0], exp[3]==y?val[1][0]:inf});
			ans[0][1]=min({val[0][0]+1, ans[0][2], x==exp[4]?val[0][1]:inf});
			ans[0][0]=min({ans[1][0], ans[0][1], x==y?val[0][0]:inf});
			return ans;
		}
	}now, sta[15000];
	inline bool operator < (dp a, dp b) {
		for (int i=0; i<3; ++i)
			for (int j=0; j<3; ++j)
				if (a[i][j]!=b[i][j])
					return a[i][j]<b[i][j];
		for (int i=1; i<=4; ++i) if (a.exp[i]!=b.exp[i]) return a.exp[i]<b.exp[i];
		return 0;
	}
	map<dp, int> mp;
	struct matrix{
		int n, m;
		ll a[150][150];
		matrix() {n=m=0; memset(a, 0, sizeof(a));}
		matrix(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
		void resize(int x, int y) {n=x; m=y; /* memset(a, 0, sizeof(a)); */}
		inline ll* operator [] (int t) {return a[t];}
		inline void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<setw(5)<<a[i][j]<<' '; cout<<endl;}cout<<endl;}
		inline matrix operator * (matrix b) {
			matrix ans(n, b.m);
			for (int i=1; i<=n; ++i)
				for (int k=1; k<=m; ++k)
					for (int j=1; j<=b.m; ++j)
						ans[i][j]=(ans[i][j]+a[i][k]*b[k][j])%mod;
			return ans;
		}
	}mat, tr;
	inline matrix qpow(matrix a, ll b) {matrix ans=a; for (--b; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}
	void dfs(int u, int lim) {
		if (u>4) {
			now[2][0]=now[0][2]=2;
			now[1][0]=2-(now.exp[1]==now.exp[2]||now.exp[1]==now.exp[4]);
			now[0][1]=2-(now.exp[1]==now.exp[2]||now.exp[2]==now.exp[3]);
			now[0][0]=min({now[1][0], now[0][1], 2ll-(now.exp[1]==now.exp[2])-(now.exp[3]==now.exp[4])});
			// now[0][0]=min({now.exp[1]==now.exp[2]&&now.exp[3]==now.exp[4]?0ll:2ll, 2ll-(now.exp[1]==now.exp[4]||now.exp[3]==now.exp[4]), 2ll-(now.exp[3]==now.exp[2]||now.exp[3]==now.exp[4]), now[1][0], now[0][1]});
			sta[++top]=now; mp[now]=top;
			dat[top]=lim<=m;
			for (int i=0; i<lim; ++i) dat[top]=dat[top]*(m-i)%mod;
			return ;
		}
		for (int i=1; i<=lim+1; ++i) now.exp[u]=i, dfs(u+1, max(lim, i));
	}
	void extend() {
		for (int i=1; i<=top; ++i) {
			int lim=max({sta[i].exp[1], sta[i].exp[2], sta[i].exp[3], sta[i].exp[4]});
			for (int x=1; x<=lim+1; ++x) {
				for (int y=1; y<=lim+1||y<=x+1; ++y) {
					// cout<<"calc: "<<i<<' '<<x<<' '<<y<<endl;
					now=sta[i].calc(x, y);
					if (now[0][0]>2) continue;
					if (mp.find(now)==mp.end()) {
						// cout<<"---now---"<<endl; now.put();
						sta[++top]=now; mp[now]=top;
						ll tem=lim<=m;
						for (int j=0; j<lim; ++j) tem=tem*(m-j)%mod;
					}
					int tem=max({lim, x, y});
					ll val=tem<=m;
					for (int i=lim; i<tem; ++i) val=val*(m-i)%mod;
					(tr[i][mp[now]]+=val)%=mod;
				}
			}
		}
	}
	void solve() {
		dfs(1, 0);
		// cout<<"top: "<<top<<endl;
		// for (int i=1; i<=top; ++i) sta[i].put();
		extend();
		mat.resize(1, top); tr.resize(top, top);
		for (int i=1; i<=top; ++i) mat[1][i]=dat[i];
		if (n>2) mat=mat*qpow(tr, n-2);
		// cout<<"dat: "; for (int i=1; i<=top; ++i) cout<<dat[i]<<' '; cout<<endl;
		for (int i=1; i<=top; ++i) ans=(ans+mat[1][i])%mod;
		printf("%lld\n", (ans%mod+mod)%mod);
	}
}

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

	n=read(); m=read();
	// force::solve();
	task::solve();
	
	return 0;
}
posted @ 2022-07-20 15:23  Administrator-09  阅读(4)  评论(0编辑  收藏  举报