大意:给你(K)个(1)到(n)的排列,让你求([L,R])的序列的操作方案数。
限定条件:每次操作只能取那些序列中的队首,且取出来组成的序列中不存在连续(R-L+1)个连续的相同的数。
(n,K<=300)
(Solution)
这题可想到平面上只能向右向下走,有若干个障碍,从((1,1))走到((n,m))的方案数。
考虑容斥,设(f[i])表示当前([l,r])区间中取出来的操作中第一次出现连续的(r-l+1)个连续相同数为(i),且考虑(i)的取出顺序而不考虑(i)以后的那些数的取出顺序的方案数。
则(f[i])可以由取(i)以前的数的总方案数减去前面更早出现了连续(r-l+1)个连续相同数的方案数。
简而言之,若([l,r])区间内存在(j)使得在其中每个序列内(j)的出现位置都比(i)要前,则(f[i])需减去(f[j]*h(j,i))。
其中(h(j,i))表示(j)到(i)之间的那些数的取出方案数。
对于容斥,我们对(i)在新的(第(r)个)序列中的位置从小到大来进行操作,这样可以保证以前的所有(f[j])都是包含新的(第(r)个)序列的第一次出现的连续的(r-l+1)个连续相同的数的方案数。
这样我们就不会算重或算漏了。
为了方便,我们在每个序列后面添加一个(n+1),这样对于每个([l,r])区间的答案就应当是(f[n+1]*ny[r-l+1])了(由于答案不需要考虑(n+1)的取出顺序)。
则最终的答案就是(sum f[n+1])。
上述容斥的时间复杂度为(O(K^2*K*n^2)),显然会(TLE)。
(也可用维护那些组合数来达到(O(K^2*n^2))的效果,但(TLE)在所难免)
既然没有天时和人和,我们尝试地利(↓):
既然是说了独立的随机的排列。那对于([L,R])区间中仍能保证一对((j,i))的(j)总是在(i)前面的是少之又少,期望是每次个数都(div 2)。
这样我们可以直接存储下来对于每个(x)当前仍符合条件的(y),然后每次操作后改删的删除即可。
时间复杂度大约为(O(n*K*(n+K)))。
但是,很容易(TLE),第一发(TLE90)了。
尝试(AC)中。。。代码待更。。。
已(AC)(果然还是(int)和(1LL)大法好)
(Code)
#include <cstdio>
#define N 310
#define mo 1000000007
#define ll long long
#define fo(x, a, b) for (int x = (a); x <= (b); x++)
#define fd(x, a, b) for (int x = (a); x >= (b); x--)
using namespace std;
int K, n, a[N][N], b[N][N], hav;
int qian_[N], qn[N][N], pl[N][N], cnt[N], f[N];
int value[N], val[N][N], jc[N * N], ny[N * N], ans = 0;
inline int read() {
int x = 0, f = 0; char c = getchar();
while (c < '0' || c > '9') f = (c == '-') ? 1 : f, c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return f ? -x : x;
}
int ksm(int x, int y) {
int s = 1;
while (y) {
if (y & 1) s = 1LL * s * x % mo;
x = 1LL * x * x % mo, y >>= 1;
}
return s;
}
void prepare() {
jc[0] = ny[0] = 1;
fo(i, 1, 90000) jc[i] = 1LL * jc[i - 1] * i % mo;
ny[90000] = ksm(jc[90000], mo - 2);
fd(i, 89999, 1) ny[i] = 1LL * ny[i + 1] * (i + 1) % mo;
}
inline ll C(int x, int y) {return 1LL * jc[y] * ny[x] % mo * ny[y - x] % mo;}
int main()
{
freopen("nothard.in", "r", stdin);
freopen("nothard.out", "w", stdout);
prepare();
K = read(), n = read();
fo(i, 1, K) {
fo(j, 1, n) a[i][j] = read(), pl[i][a[i][j]] = j;
a[i][n + 1] = n + 1, pl[i][n + 1] = n + 1;
}
n++;
fo(L, 1, K - 1) {
fo(i, 1, n) f[i] = cnt[i] = 0; f[a[L][1]] = 1;
fo(i, 1, n) value[a[L][i]] = 1, qian_[a[L][i]] = i - 1;
fo(j, 2, n) fo(i, 1, j - 1) {
int x = a[L][j]; b[x][++cnt[x]] = a[L][i];
qn[x][cnt[x]] = j - i - 1, val[x][cnt[x]] = 1;
}
fo(R, L + 1, K) {
fo(i, 1, n) {
int x = a[R][i]; qian_[x] += i - 1;
value[x] = 1LL * value[x] * C(i - 1, qian_[x]) % mo;
f[x] = value[x];
}
fo(i, 1, n) {
int x = a[R][i];
fo(j, 1, cnt[x]) {
if (i < pl[R][b[x][j]]) {
b[x][j] = b[x][cnt[x]], qn[x][j] = qn[x][cnt[x]];
val[x][j] = val[x][cnt[x]], cnt[x]--; j--; continue;
}
// printf("%d %d
", pl[R][b[x][j]], i);
int t = i - pl[R][b[x][j]] - 1;
val[x][j] = 1LL *val[x][j] * C(t, qn[x][j] + t) % mo; qn[x][j] += t;
f[x] = f[x] + mo - 1LL * val[x][j] * f[b[x][j]] % mo;
if (f[x] >= mo) f[x] -= mo;
}
f[x] = 1LL * f[x] * jc[R - L + 1] % mo;
}
// printf("%d %d: %lld
", L, R, f[n]);
ans = (ans + 1LL * f[n] * ny[R - L + 1]) % mo;
}
}
printf("%d
", ans);
return 0;
}