题解:AT_code_festival_2017_qualc_f Three Gluttons
考虑充要条件。但你直接对着这三个序列硬想是没有前途的,我们考虑增加一些信息创造入手点。
考虑已知三个人依次吃掉的寿司下标,令
- 对任意
i_t ,A_{i_t} 在B_{1\dots j_t} 和C_{1\dots k_t} 中没有出现过。我们称该限制为“A 寿司对B/C 序列的限制”。B_j,C_k 同理。
若已知吃掉的寿司,能否计算
只需对吃掉的寿司计数。“
考虑已知吃掉的
预处理
总结:本题需灵活转换计数对象,增加或减少枚举信息。难以下手,便添加“吃掉的寿司”这一信息。后面发现难以直接记录
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 4e2 + 5, mod = 1e9 + 7;
int n, a[N], b[N], ap[N], bp[N], f[N][N], _f[N][N], g[N][N], buc[N];
signed main(){
cin >> n;
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]), ap[a[i]] = i;
for(int i = 1; i <= n; ++i) scanf("%d", &b[i]), bp[b[i]] = i;
if(a[1] == b[1]) {puts("0"); return 0;}
for(int i = 1; i <= n; ++i){
int ct = 0;
for(int j = 1; j <= n; ++j) buc[j] = (ap[j] <= i), ct += buc[j];
for(int j = 1; j <= n; ++j) ct += (buc[b[j]] == 0), g[i][j] = ct;
}
f[1][1] = 1;
for(int t = 2; t <= n / 3; ++t){
for(int i = 1; i <= n; ++i)
for(int j = 1, s = 0; j <= n; ++j){
_f[i][j] = f[i][j];
s = (s + f[i][j]) % mod;
_f[i][j] = (_f[i - 1][j] + s) % mod;
f[i][j] = 0;
}
for(int i = t; i <= n; ++i)
for(int j = t; j <= n; ++j){
if(ap[b[j]] <= i || bp[a[i]] <= j) continue;
if(g[i][j] < 3 * t) f[i][j] = 1ll * _f[i - 1][j - 1] * (3ll * t - g[i][j]) % mod;
}
}
int ans = 0;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
ans = (ans + f[i][j]) % mod;
for(int i = 1; i <= n / 3; ++i) ans = 1ll * ans * (3 * i - 1) * (3 * i - 2) % mod;
cout << ans;
return 0;
}