题解 相似序列问题 / 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;
}