zoukankan      html  css  js  c++  java
  • LOJ#6077. 「2017 山东一轮集训 Day7」逆序对(容斥+生成函数+动态规划)

    LOJ#6077. 「2017 山东一轮集训 Day7」逆序对(容斥+生成函数+动态规划)

    题目大意

    给定 (n)(k) ,请求出长度为 (n) 的逆序对数恰好为 (k) 的排列的个数。答案对 P 取模。

    数据范围

    对于 100% 的数据,(1 le n,k le 100000)

    解题思路

    很好的计数题

    两种思路

    生成函数

    第 i 个元素对答案的贡献为 ([0, i-1]),其生成函数为

    [(1)*(1+x^1)*(1+x^2+x^3)cdots(1+x^2+cdots+x^{n-1})=frac {prod(1-x^i)}{(1-x)^n}\ frac 1{(1-x)^n}=(1+x+x^2+cdots)^n ]

    由此可知,分母的 x 项就是 (x + n-1choose n-1) (隔板法)

    分子可以视为用 x 个数凑出和为 s 的方案数,同时 x 为奇数 s 就是负的

    只需求出 (g[i] = sum_{i=0} (-1)^i*f[i][s])

    (Ans = sum_{i=0}g[i]*{k - i + n - 1 choose n-1})

    容斥

    枚举有 k 个元素超出贡献

    [Ans = sum_{i=0}sum_{j=0}^k(-1)^i*f[i][j]*{k-j+n-1choose n-1} ]

    算 f 数组

    不难发现,i 的最大值大概在 (sqrt n) 附近,因为是 x 个不相同的正整数

    暴力转移跑背包的复杂度是 (Theta(n^2sqrt n)) 的,不行啊

    由于 “体积” 是连续整数,我们有如下方法

    设当前已选集合 S

    • 将 S 集合中的数都 +1,(f[x][s] + f[x][s-x])
    • 将 S 集合中的数都 +1 并将 1 插入 S 集合,(f[x][s] + f[x-1][s-x])
    • +1 时最后一位有可能大于 n,将它减掉 (f[x][s] - f[x-1][s-n-1])

    据以上分析,可由 (Theta(n sqrt n)) 的时间复杂度求出答案

    带码

    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MP make_pair
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template<typename F>
    inline void write(F x)
    {
    	static short st[30];short tp=0;
    	if(x<0) putchar('-'),x=-x;
    	do st[++tp]=x%10,x/=10; while(x);
    	while(tp) putchar('0'|st[tp--]);
    	putchar('
    ');
    }
    
    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y); }
    
    template <typename T>
    inline void Mn(T &x, T y) { x > y && (x = y); }
    
    const int P = 1e9+7;
    const int N = 200050;
    const int M = 450;
    ll jie[N], inv[N], ans;
    ll f[M][N], n, k;
    ll C(ll n, ll m) {
    	return jie[n] * inv[n-m] % P * inv[m] % P;
    }
    
    int main() {
    	read(n), read(k);
    	inv[0] = jie[0] = inv[1] = jie[1] = 1;
    	for (int i = 2;i <= n + k; i++)
    		jie[i] = jie[i-1] * i % P,
    		inv[i] = (P - P / i) * inv[P%i] % P;
    	for (int i = 2;i <= n + k; i++)
    		inv[i] = inv[i-1] * inv[i] % P;
    	f[0][0] = 1; int lim = M;
    	for (int i = 1;i < lim; i++) {
    		for (int j = i;j <= k; j++) {
    			f[i][j] = (f[i][j] + f[i][j-i] + f[i-1][j-i]) % P;
    			if (j > n) f[i][j] = (f[i][j] + P - f[i-1][j-n-1]) % P;
    //			cout << f[i][j] << ' ';
    		}
    	}
    	for (int i = 0;i <= k; i++) {
    		ll res = 0;
    		for (int j = 0;j < lim; j++)
    			j & 1 ? res -= f[j][i] : res += f[j][i];
    		res = (res % P + P) % P; 
    		ans = (ans + res * C(k - i + n - 1, n - 1)) % P;
    	}
    	write(ans);
    	return 0;
    }
    

    ------------恢复内容开始------------

    LOJ#6077. 「2017 山东一轮集训 Day7」逆序对(容斥+生成函数+动态规划)

    题目大意

    给定 (n)(k) ,请求出长度为 (n) 的逆序对数恰好为 (k) 的排列的个数。答案对 P 取模。

    数据范围

    对于 100% 的数据,(1 le n,k le 100000)

    解题思路

    很好的计数题

    两种思路

    生成函数

    第 i 个元素对答案的贡献为 ([0, i-1]),其生成函数为

    [(1)*(1+x^1)*(1+x^2+x^3)cdots(1+x^2+cdots+x^{n-1})=frac {prod(1-x^i)}{(1-x)^n}\ frac 1{(1-x)^n}=(1+x+x^2+cdots)^n ]

    由此可知,分母的 x 项就是 (x + n-1choose n-1) (隔板法)

    分子可以视为用 x 个数凑出和为 s 的方案数,同时 x 为奇数 s 就是负的

    只需求出 (g[i] = sum_{i=0} (-1)^i*f[i][s])

    (Ans = sum_{i=0}g[i]*{k - i + n - 1 choose n-1})

    容斥

    枚举有 k 个元素超出贡献

    [Ans = sum_{i=0}sum_{j=0}^k(-1)^i*f[i][j]*{k-j+n-1choose n-1} ]

    算 f 数组

    不难发现,i 的最大值大概在 (sqrt n) 附近,因为是 x 个不相同的正整数

    暴力转移跑背包的复杂度是 (Theta(n^2sqrt n)) 的,不行啊

    由于 “体积” 是连续整数,我们有如下方法

    设当前已选集合 S

    • 将 S 集合中的数都 +1,(f[x][s] + f[x][s-x])
    • 将 S 集合中的数都 +1 并将 1 插入 S 集合,(f[x][s] + f[x-1][s-x])
    • +1 时最后一位有可能大于 n,将它减掉 (f[x][s] - f[x-1][s-n-1])

    据以上分析,可由 (Theta(n sqrt n)) 的时间复杂度求出答案

    带码

    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MP make_pair
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template<typename F>
    inline void write(F x)
    {
    	static short st[30];short tp=0;
    	if(x<0) putchar('-'),x=-x;
    	do st[++tp]=x%10,x/=10; while(x);
    	while(tp) putchar('0'|st[tp--]);
    	putchar('
    ');
    }
    
    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y); }
    
    template <typename T>
    inline void Mn(T &x, T y) { x > y && (x = y); }
    
    const int P = 1e9+7;
    const int N = 200050;
    const int M = 450;
    ll jie[N], inv[N], ans;
    ll f[M][N], n, k;
    ll C(ll n, ll m) {
    	return jie[n] * inv[n-m] % P * inv[m] % P;
    }
    
    int main() {
    	read(n), read(k);
    	inv[0] = jie[0] = inv[1] = jie[1] = 1;
    	for (int i = 2;i <= n + k; i++)
    		jie[i] = jie[i-1] * i % P,
    		inv[i] = (P - P / i) * inv[P%i] % P;
    	for (int i = 2;i <= n + k; i++)
    		inv[i] = inv[i-1] * inv[i] % P;
    	f[0][0] = 1; int lim = M;
    	for (int i = 1;i < lim; i++) {
    		for (int j = i;j <= k; j++) {
    			f[i][j] = (f[i][j] + f[i][j-i] + f[i-1][j-i]) % P;
    			if (j > n) f[i][j] = (f[i][j] + P - f[i-1][j-n-1]) % P;
    //			cout << f[i][j] << ' ';
    		}
    	}
    	for (int i = 0;i <= k; i++) {
    		ll res = 0;
    		for (int j = 0;j < lim; j++)
    			j & 1 ? res -= f[j][i] : res += f[j][i];
    		res = (res % P + P) % P; 
    		ans = (ans + res * C(k - i + n - 1, n - 1)) % P;
    	}
    	write(ans);
    	return 0;
    }
    
  • 相关阅读:
    网络模块axios的简单应用
    UWP App国际化的两种实现
    C# 显示函数调用方的详细信息
    UWP SVG 转 Glyph
    UWP 区分设备类型
    Flutter 星标已正式超过React Native
    查看Github星标排行榜
    博客园部分非公开api
    模块化(零):综述
    模块化一:提取模块
  • 原文地址:https://www.cnblogs.com/Hs-black/p/12854642.html
Copyright © 2011-2022 走看看