zoukankan      html  css  js  c++  java
  • bzoj5161 最长上升子序列 状压DP(DP 套 DP) + 打表

    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=5161

    题解

    回顾一下以前用二分求 LIS 的方法:令 (f[i]) 表示长度为 (i) 的 LIS 的最后一位的最小值。可发现不管目前 DP 到了哪儿,这个东西永远是递增的。


    关于 LIS 的题目的大都可以维护一些和这个东西有关的状态,所以我们考虑状压这个数组。因为这个数组中每一位都不重复,所以可以用 (01) 来状压成一个二进制数。

    由于我们在转移状态的时候,不关系新来的数到底是几,只关心这个新来的数和之前的数的大小关系,所以我们可以修改之前的 (f) 的定义为最后一位是已经 DP 过的数中第几小的数。

    这样,新插入一个数的时候,可以枚举它的大小的排名,然后替换掉它后一名的数,并把后面的数全部 (+1),这个可以通过二进制数的移位实现。

    最后 (dp[n][2^n - 1]) 就是答案。


    因为在第 (i) 位的时候,状态只需要枚举到 (2^i),所以总的复杂度为 (O(n(2^0 + 2^1 + 2^2 + cdots)) = O(n2^n))

    但是 (O(n2^n))(n leq 28) 面前显得苍白无力。怎么办呢?

    (n = 28) 的时候 (28 imes 2^{28}) 大概是 (7e9) 左右,一分钟以内可以跑完。所以,可以花一点出去 orz​ 别的神仙的时间(大概 (2-3min))来打一个表。

    然后就可以通过这道题了。


    正常代码

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    #define lowbit(x) ((x) & -(x))
    
    const int N = 28 + 7;
    const int M = (1 << 27) + 7;
    const int P = 998244353;
    
    int n, S;
    int dp[2][M], pcnt[M], suf[N];
    
    inline int smod(int x) { return x >= P ? x - P : x; }
    inline void sadd(int &x, const int &y) { x += y; x >= P ? x -= P : x; }
    inline int fpow(int x, int y) {
    	int ans = 1;
    	for (; y; y >>= 1, x = (ll)x * x % P) if (y & 1) ans = (ll)ans * x % P;
    	return ans;
    }
    
    inline void ycl() {
    	S = (1 << (n - 1)) - 1;
    	for (int s = 1; s <= S; ++s) pcnt[s] = pcnt[s ^ lowbit(s)] + 1;
    }
    
    inline void work() {
    	ycl();
    	int now = 1, pp = 0;
    	dp[now][0] = 1;
    	for (int i = 1; i < n; ++i) {
    		std::swap(now, pp);
    		for (int s = 0; s < (1 << i); ++s) dp[now][s] = 0;
    		for (int sss = 0; sss < (1 << (i - 1)); ++sss) {
    			int pre = 0, s = sss << 1 | 1;
    			for (int j = i; j; --j) suf[j] = (s >> (j - 1)) & 1 ? j : suf[j + 1];
    			for (int j = 0; j <= i; ++j) {
    				if (j) pre += (s >> (j - 1)) & 1;
    				int ss, sta, p = suf[j + 1];
    				if (p) ss = s ^ (1 << (p - 1));
    				sta = (s & ((1 << j) - 1)) | ((ss & ~((1 << j) - 1)) << 1) | (1 << j);
    				sadd(dp[now][sta >> 1], dp[pp][sss]);
    			}
    		}
    	}
    	int ans = 0;
    	for (int i = 0; i <= S; ++i) sadd(ans, (ll)(pcnt[i] + 1) * dp[now][i] % P);
    	for (int i = 1; i <= n; ++i) ans = (ll)ans * fpow(i, P - 2) % P;
    	printf("%d
    ", ans);
    }
    
    inline void init() {
    	read(n);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    

    打表代码

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    #define lowbit(x) ((x) & -(x))
    
    const int N = 28 + 7;
    const int M = (1 << 27) + 7;
    const int P = 998244353;
    const int ans[] = {0, 1, 499122178, 2, 915057326, 540715694, 946945688, 422867403, 451091574, 317868537, 200489273, 976705134, 705376344, 662845575, 331522185, 228644314, 262819964, 686801362, 495111839, 947040129, 414835038, 696340671, 749077581, 301075008, 314644758, 102117126, 819818153, 273498600, 267588741};
    
    int n, S;/*
    int dp[2][M], pcnt[M], suf[N];
    
    inline int smod(int x) { return x >= P ? x - P : x; }
    inline void sadd(int &x, const int &y) { x += y; x >= P ? x -= P : x; }
    inline int fpow(int x, int y) {
    	int ans = 1;
    	for (; y; y >>= 1, x = (ll)x * x % P) if (y & 1) ans = (ll)ans * x % P;
    	return ans;
    }
    
    inline void ycl() {
    	S = (1 << (n - 1)) - 1;
    	for (int s = 1; s <= S; ++s) pcnt[s] = pcnt[s ^ lowbit(s)] + 1;
    }
    
    inline void work() {
    	ycl();
    	int now = 1, pp = 0;
    	dp[now][0] = 1;
    	for (int i = 1; i < n; ++i) {
    		std::swap(now, pp);
    		for (int s = 0; s < (1 << i); ++s) dp[now][s] = 0;
    		for (int sss = 0; sss < (1 << (i - 1)); ++sss) {
    			int pre = 0, s = sss << 1 | 1;
    			for (int j = i; j; --j) suf[j] = (s >> (j - 1)) & 1 ? j : suf[j + 1];
    			for (int j = 0; j <= i; ++j) {
    				if (j) pre += (s >> (j - 1)) & 1;
    				int ss, sta, p = suf[j + 1];
    				if (p) ss = s ^ (1 << (p - 1));
    				sta = (s & ((1 << j) - 1)) | ((ss & ~((1 << j) - 1)) << 1) | (1 << j);
    //				dbg("i = %d, s = %d, j = %d, sta = %d, now = %d, pre = %d
    ", i, s, j, sta, now, pp);
    				sadd(dp[now][sta >> 1], dp[pp][sss]);
    			}
    		}
    	}
    	int ans = 0;
    	for (int i = 0; i <= S; ++i) sadd(ans, (ll)(pcnt[i] + 1) * dp[now][i] % P);
    	for (int i = 1; i <= n; ++i) ans = (ll)ans * fpow(i, P - 2) % P;
    	printf("%d
    ", ans);
    }*/
    
    inline void work() {
    	printf("%d
    ", ans[n]);
    }
    
    inline void init() {
    	read(n);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    Python之路Day11
    Python之路Day10
    Python中需要注意的一些小坑
    Python之路Day09
    Python之路Day08
    关于谷歌浏览器安装非官方商城插件
    Python之路Day07
    Python之路Day06
    Python之路Day05
    Python 之路Day04
  • 原文地址:https://www.cnblogs.com/hankeke/p/bzoj5161.html
Copyright © 2011-2022 走看看