zoukankan      html  css  js  c++  java
  • [SRM625 Div1 Hard] Seatfriends

    题目链接:Portal Vjudge

    Solution

    一开始拿到这一题Sb了,把空放到dp中一起考虑了,这样计数就变得很麻烦。

    其实我们可以把空位拿出来,假设它是存在的,最后再放回去。

    那么就可以钦定某个人放到第一个,因为这是环排列,所以最后乘以n就可以了。

    (Dp[i][j])表示来了(i)个人,分成(j)个联通块的方案数。

    那么新来的人有三种选择,加入一个联通块,独立成为一个联通块,合并两个联通块:

    [Dp[i + 1][j + 1] += dp[i][j] * j\ Dp[i + 1][j - 1] += dp[i][j] * j\ Dp[i + 1][j] += dp[i][j] * 2j ]

    最后利用隔板法:$$ ans = nsum_{i = 1}^{G} dp[m][i] * {n - k - 1 choose i - 1}$$

    一般环排列有空的计数,可以把空位全部抽出来计数,并且在计数过程中假定空存在,最后再用隔板法插入。

    如果所求排列是环排列,那就钦定一种选法然后乘上环的大小即可。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
    #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
    #define clar(a, b) memset((a), (b), sizeof(a))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    typedef long long LL;
    typedef long double LD;
    
    const int Maxn = 4009, Mod = 1e9 + 7;
    class Seatfriends {
    	private:
    		int dp[Maxn][Maxn];
    		int invFac[Maxn], fac[Maxn];
    	public:
    		int fpm(int base, int tims) {
    			int r = 1;
    			while (tims) {
    				if (tims & 1) r = r * 1ll * base % Mod;
    				base = base * 1ll * base % Mod;
    				tims >>= 1;
    			}
    			return r;
    		}
    		int C(int n, int m) {
    			if (m > n) return 0;
    			return fac[n] *1ll * invFac[m] % Mod * invFac[n - m] % Mod;
    		}
    
    		void init(int n) {
    			fac[0] = 1;
    			rep (i, 1, n) fac[i] = 1ll * fac[i - 1] * i % Mod;
    			invFac[n] = fpm(fac[n], Mod - 2);
    			drep (i, n - 1, 0) invFac[i] = invFac[i + 1] * (i + 1ll) % Mod;
    		}
    
    		int countseatnumb(int n, int k, int g) {
    			init(n + k); clar(dp, 0);
    			dp[1][1] = 1;
    			rep (i, 1, k)
    				rep (j, 1, g)
    					if (dp[i][j]) {
    						(dp[i + 1][j + 1] += 1ll * dp[i][j] * j % Mod) %= Mod;
    						(dp[i + 1][j] += 2ll * j % Mod * dp[i][j] % Mod) %= Mod;
    						if (j > 1) (dp[i + 1][j - 1] += 1ll * dp[i][j] * j % Mod) %= Mod;
    					}
    			LL ans = 0;
    			if (n == k) return (g >= 1) * dp[k - 1][1] * 1ll * n % Mod;
    			rep (i, 1, g) ans = (ans + 1ll * dp[k][i] * C(n - k - 1, i - 1) % Mod) % Mod;
    			return ans * 1ll * n % Mod;
    		}
    };
    
  • 相关阅读:
    关于s3c6410 实现opengl的分析
    ARM9和ARM11的区别
    ARM9E 和 cortex a8 NEON 优化效率的对比
    armv6 的特点
    AMBA总线新一代标准AXI分析和应用
    linux下如何模拟按键输入和模拟鼠标
    opengl es 学习
    Jlink初使用
    Allegro 制作金手指封装
    世界之窗浏览器设置google搜索[转]
  • 原文地址:https://www.cnblogs.com/qrsikno/p/10161728.html
Copyright © 2011-2022 走看看