Bessie的玩具箱里有N种(编号1至N)不同颜色的积木,第i种颜色的积木有a[i]个。每个积木就是一个1×1×1的正方体。刚开始,地板上没有任何的积木,Bessie每次从箱子里挑出一个积木(选择顺序由Bessie决定),然后有两种选择:
1、把这个积木直接放在地板上;
2、把这个积木叠放在之前已经放置好的某个积木正上方。
Bessie最终会把玩具箱里所有的积木全部拿出来,在地板上搭建积木塔。Bessie在搭建积木塔时还遵守一个规则:相同颜色的积木所处的水平高度必须相等。地板的水平高度是0,地板上方第一层的所有积木的水平高度都是1,地板上方第二层的所有积木的水平高度都是2,依次类推。
Bessie的朋友Andy来了,Andy是要把Bessie的积木塔通过N次操作后全部移走,Andy每次选择一种颜色k,然后把颜色是k的所有积木都从积木塔中移走,但是能进行这个操作的前提条件是:颜色是k的所有积木的上方都没有其他积木了。简单点说,Andy移走积木塔的整个过程就是这N种颜色的一个排列!对于Bessie的积木塔,Andy的不同移走方案,其实就是对应这N种颜色的不同的排列!
现在Bessie和Andy玩游戏,Bessie搭建好积木塔后,Andy就计算把积木塔移走的不同方案数(即上文提及的合法的N种颜色的不同排列的数量),不妨假设Andy算出的不同方案数是s, 如果s的范围在区间[minWays,maxWays]范围内,那么Bessie搭建的积木塔是“好塔”,否则就不是。然后Andy就把移走的积木塔打乱,重新放回Bessie的玩具箱里。然后他们又开始重复玩这个游戏,Bessie搭积木塔,Andy针对当前积木塔计算不同移走方案数,判断Bessie搭建的是不是“好塔”,然后把积木塔打乱,重新放回玩具箱….,他们不断重复这个游戏。
Bessie保证每次新搭建的积木塔和之前搭建的所有积木塔都是“本质不同”的!如果Bessie做不到这点,游戏就会结束!
下面定义“本质不同”:假设有积木塔A和积木塔B,只要存在不同的颜色i和颜色j,在积木塔A中至少有一个颜色i的积木“直接”铺在颜色j的积木的正上方,而在积木塔B中不存在颜色i的积木“直接”铺在颜色j的积木的正上方,那么积木塔A和积木塔B是“本质不同”的,否则A和B是本质相同的。“直接”的意思是指两个积木高度差距是1。
现在的问题是:Bessie能构造出多少个“本质不同”的“好塔”?答案模1000000007。
LJ搜索题。
如果把x颜色放y上面视作x到y连一条边。
则该图的可能数是 3n∗(n−1)/2=315=14348907 3 n ∗ ( n − 1 ) / 2 = 3 15 = 14348907
发现不能有环,少了很多。
由于一个颜色的点的高度必须相同,又少了很多。
还剩6w+个图。
这个图就一定合法吗?不能。
分层跑最大流可以判合法。
方案数呢,暴力 6!=720 6 ! = 720 ,心态稳健。
Code:
#include
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
const int inf = 1 << 30;
int n, a[10], mi, mx, b[10][10], tb, du[10], d[10], dis[10];
const int M = 1000;
int final[M], next[M], to[M], r[M], tot = 1, S, T, co[M], dt[M], cur[M];
void cl() {
fo(i, 1, T) final[i] = dt[i] = co[i] = cur[i] = 0;
fo(i, 2, tot) next[i] = 0;
tot = 1;
}
void link(int x, int y, int z) {
next[++ tot] = final[x], to[tot] = y, r[tot] = z, final[x] = tot;
next[++ tot] = final[y], to[tot] = x, r[tot] = 0, final[y] = tot;
}
int dfs(int x, int flow) {
if(x == T) return flow;
int use = 0;
for(int i = cur[x]; i; i = next[i], cur[x] = i) {
int y = to[i];
if(r[i] && dt[y] + 1 == dt[x]) {
int tmp = dfs(y, min(flow - use, r[i]));
r[i] -= tmp, r[i ^ 1] += tmp, use += tmp;
if(use == flow) return use;
}
}
cur[x] = final[x];
if(!(-- co[dt[x]])) dt[S] = T;
++ co[++ dt[x]];
return use;
}
int p[10][10], q[10];
int bz[10], ans, sum;
void dd(int x) {
if(x > n) {
sum ++; return;
}
fo(i, 1, n) if(!bz[i]) {
int ky = 1;
fo(j, 1, b[i][0]) if(bz[b[i][j]]) {
ky = 0; break;
}
if(ky) bz[i] = 1, dd(x + 1), bz[i] = 0;
}
}
void dg(int x, int y) {
if(tb > 9) return;
if(x > n) {
d[0] = 0; fo(i, 1, n) du[i] = 0;
fo(i, 1, n) fo(j, 1, b[i][0]) du[b[i][j]] ++;
fo(i, 1, n) if(!du[i]) d[++ d[0]] = i;
fo(i, 1, d[0]) fo(j, 1, b[d[i]][0]) if(!(-- du[b[d[i]][j]])) d[++ d[0]] = b[d[i]][j];
if(d[0] != n) return;
int dep = 0;
fd(i, d[0], 1) {
if(!b[d[i]][0]) {dis[d[i]] = 1; continue;}
int y = dis[b[d[i]][1]];
fo(j, 2, b[d[i]][0]) if(y != dis[b[d[i]][j]]) return;
dis[d[i]] = y + 1;
}
fo(i, 1, n) p[i][0] = q[i] = 0;
fo(i, 1, n) p[dis[i]][++ p[dis[i]][0]] = i, dep = max(dep, dis[i]);
fo(i, 2, dep) {
cl();
int tmp = 0;
fo(j, 1, p[i][0]) {
int x = p[i][j];
tmp += a[x] - b[x][0];
if(a[x] < b[x][0]) return;
link(S, x, a[x] - b[x][0]);
fo(k, 1, b[x][0]) link(x, b[x][k], inf), q[b[x][k]] ++;
}
fo(j, 1, p[i - 1][0]) {
int x = p[i - 1][j];
if(a[x] < q[x]) return;
if(a[x] > q[x]) link(x, T, a[x] - q[x]);
}
co[0] = T; int fw = 0;
for(; dt[S] < T;) fw += dfs(S, inf);
if(fw < tmp) return;
}
sum = 0; dd(1);
if(sum >= mi && sum <= mx) ans ++;
return;
}
if(y > n) {
dg(x + 1, x + 2);
return;
}
tb ++;
b[x][++ b[x][0]] = y;
dg(x, y + 1); b[x][0] --;
b[y][++ b[y][0]] = x;
dg(x, y + 1); b[y][0] --;
tb --;
dg(x, y + 1);
}
int main() {
scanf("%d", &n);
fo(i, 1, n) scanf("%d", &a[i]);
scanf("%d %d", &mi, &mx);
S = n + 1; T = n + 2;
dg(1, 2);
printf("%d\n", ans);
}