zoukankan      html  css  js  c++  java
  • 洛谷P4707 重返现世(扩展min-max容斥+背包dp+拆组合数)

    https://www.luogu.com.cn/problem/P4707

    题解:

    扩展min-max容斥见:
    https://www.cnblogs.com/coldchair/p/13404911.html

    一开始使(k=n-k+1),意义转为第(k)大。

    然后套容斥:
    (sum_{T} min(T)*inom{|T|-1}{k-1}*(-1)^{|T|-k})

    在此题中,很容易得到(min(T)=frac{m}{sum{x in T} ~ a[x]})

    考虑一个dp,(f[i][j][u])表示前(i)个确定了,(|T|=j)(sum{x in T} ~ a[x]=u)的方案数,可以获得70p。

    ((-1)^{|T|-k})可以放进dp里。

    注意到(kle 10),观察(inom{|T|-1}{k-1}),联想到组合数性质:(inom{A+1}{B}= inom{A}{B-1}+ inom{A}{B})

    只要维护(inom{|T|-1}{0..k-1}),当(|T|++)时,就可以推了。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int mo = 998244353;
    
    ll ksm(ll x, ll y) {
    	ll s = 1;
    	for(; y; y /= 2, x = x * x % mo)
    		if(y & 1) s = s * x % mo;
    	return s;
    }
    
    const int N = 10005;
    
    int n, k, m;
    int a[N];
    
    ll fac[N], nf[N], inv[N];
    
    void build(int n) {
    	fac[0] = 1; fo(i, 1, n) fac[i] = fac[i - 1] * i % mo;
    	nf[n] = ksm(fac[n], mo - 2); fd(i, n, 1) nf[i - 1] = nf[i] * i % mo;
    	fo(i, 1, n) inv[i] = nf[i] * fac[i - 1] % mo;
    }
    
    ll C(int n, int m) {
    	return n < m ? 0 : fac[n] * nf[m] % mo * nf[n - m] % mo;
    }
    
    ll f[2][11][N][2];
    int o;
    
    void add(ll &x, ll y) { (x += y) %= mo;}
    
    int main() {
    	build(10000);
    	scanf("%d %d %d", &n, &k, &m);
    	fo(i, 1, n) scanf("%d", &a[i]);
    	k = n - k + 1;
    	memset(f, 0, sizeof f);
    	f[o][0][0][0] = (k % 2 ? -1 : 1);
    	int sm = 0;
    	fo(i, 1, n) {
    		memset(f[!o], 0, sizeof f[!o]);
    		fo(u, 0, sm) {
    			fo(j, 0, k - 1) {
    				add(f[!o][j][u + a[i]][1], -(f[o][j][u][1] + (j ? f[o][j - 1][u][1] : 0)));
    				add(f[!o][j][u + a[i]][1], -f[o][j][u][0]);
    				add(f[!o][j][u][0], f[o][j][u][0]);
    				add(f[!o][j][u][1], f[o][j][u][1]);
    			}
    		}
    		sm += a[i];
    		o = !o;
    	}
    	ll ans = 0;
    	fo(u, 0, m) {
    		ans = (ans + inv[u] * m % mo * f[o][k - 1][u][1]) % mo;
    	}
    	ans = (ans % mo + mo) % mo;
    	pp("%lld
    ", ans);
    }
    
  • 相关阅读:
    命运(经典dp)
    A * B Problem Plus(fft)
    Hat's Fibonacci(大数加法+直接暴力)
    Can you find it?(哈希)
    String 类型与char 类型 输入
    QT 之 QMutexLocker如何安全锁住全局变量
    C语言中access/_access函数的使用实例详解
    %02x与%2x 之间的区别
    函数名&函数名取地址
    函数指针及其定义和用法,C语言函数指针详解
  • 原文地址:https://www.cnblogs.com/coldchair/p/13406175.html
Copyright © 2011-2022 走看看