(分层图+DP)hihoCoder1147 时空阵

传送门

第二次做这道题还是不记得怎么做。。
考虑在分层图上跑dp。。
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示在前 i i i层有 j j j个点,第 i i i层有 k k k
转移方程:
i &lt; K : d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j − k ] [ x ] × C n − j + k − 1 k × ( 2 x − 1 ) k × 2 k ( k − 1 ) 2 i &lt; K : dp[i][j][k] = dp[i - 1][j - k][x]\times C_{n-j+k-1}^k\times(2^x - 1)^k\times 2^{\frac{k(k-1)}{2}} i<K:dp[i][j][k]=dp[i1][jk][x]×Cnj+k1k×(2x1)k×22k(k1)
i = K : d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j − k ] [ x ] × C n − j + k − 1 k − 1 × ( 2 x − 1 ) k × 2 k ( k − 1 ) 2 i = K : dp[i][j][k] = dp[i - 1][j - k][x]\times C_{n-j+k-1}^{k-1}\times(2^x - 1)^k\times 2^{\frac{k(k-1)}{2}} i=K:dp[i][j][k]=dp[i1][jk][x]×Cnj+k1k1×(2x1)k×22k(k1)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define For(i, l, r) for (int i = (int)(l); i <= (int)(r); ++i)
#define Rep(i, r, l) for (int i = (int)(r); i >= (int)(l); --i)
#define Pb push_back
#define Mp make_pair
#define Fi first
#define Se second
#define Gc getchar

using namespace std;
typedef long long LL;
const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const int N = 110;

int comp[N][N], dp[N][N][N], pow2[N * N];

inline void upd(int &x, int y) {x += y; x -= x >= MOD ? MOD : 0;}
inline int dec(int x, int y) {x -= y; x += x < 0 ? MOD : 0; return x;}
inline int add(int x, int y) {x += y; x -= x >= MOD ? MOD : 0; return x;}
inline int mul(int x, int y) {return 1LL * x * y % MOD;};

inline int qui_pow(int x, int y) {
    int ret = 1;
    for(; y; y >>= 1) {
        if (y & 1) ret = mul(ret, x);
        x = mul(x, x);
    }
    return ret;
}

inline void pre(int n) {
	For(i, 0, n) comp[i][0] = 1;
	For(i, 1, n) For(j, 1, i) comp[i][j] = add(comp[i - 1][j], comp[i - 1][j - 1]);
	pow2[0] = 1;
	For(i, 1, n * n) pow2[i] = mul(pow2[i - 1], 2);
}

inline LL read() {
    LL x = 0, f = 1;
    char ch = Gc();
    while (!isdigit(ch) && ch != '-') ch = Gc();
    if (ch == '-') f = -1, ch = Gc();
    while (isdigit(ch)) {x = (x << 1) + (x << 3) + (ch ^ 48); ch = Gc();}
    return x * f;
}

int main() {
	int n = read(), K = read();
	pre(n);
	dp[0][1][1] = 1;
	int ans = 0;
	For(i, 1, K) For(j, i + 1, n - K + i) For(k, 1, j - i) {
		LL now = i < K ? comp[n - j + k - 1][k] : comp[n - j + k - 1][k - 1];
		For(x, 1, j - k - i + 1) upd(dp[i][j][k], mul(dp[i - 1][j - k][x], mul(now, mul(qui_pow(pow2[x] - 1, k), pow2[comp[k][2]]))));
		if (i == K) upd(ans, mul(dp[i][j][k], pow2[k * (n - j) + comp[n - j][2]]));
	}
	printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值