BZOJ3622: 已经没有什么好害怕的了 DP

原创 2017年01月03日 17:12:55

题意:有N个糖果,N个药片,每个糖果和药片都有权值,求所有的两两配对方案中,糖 > 药的组数比药 >糖的组数多k组的方案数。n<=2000,保证所有权值不相同。
DP好题。
将问题转化为求糖 > 药的组数正好(n+k)/2组的方案数,若不是整数则显然为0。由于与顺序无关,所以可以先对两组数据排序。
接下来考虑如何设计状态。
排完序后,容易预处理出每一个糖果大于多少个药片(记为cnt[i])。设f[i][j] 为枚举到第i个糖果,糖 > 药有j组的方案数。转移:不使用第i个糖果,有f[i-1][j] 组;使用第i个糖果,先用前i-1个糖果配出j-1组,第i个糖果还能配对的有cnt[i]-j+1个。如果这个数是负数那么显然是不可行的。所以f[i][j] =f[i-1][j]+f[i-1][j-1]*max(cnt[i]-j+1,0)。
这样我们得到了“从n个糖果中选出k个,从n个药片中选出k个,配成k组糖 > 药的方案数“。但是由于我们没有考虑未被选出的糖和药以何种方式配对,所以这并不是糖 > 药恰好k对的方案数。我们先将得到的f[n][x] 乘以A(n-x,n-x),代表让没被选中的糖、药全排列,再考虑其中包含了什么样的重复元素。
从这里开始,已经用不到中间状态,只需考虑f[n][x](乘以全排列后的),所以将f[n][x]记为g[x]。
举个例子,比如现有一种糖 > 药正好为5组的既定方案,那么这种方案中任取三个糖 > 药的对子,都被作为”取3个糖 >药的配对“而在g[3]中出现过一次。
可以抽象理解一下:一个组数多于x的方案,就像一个高维物体,用x组的眼光去看它,看到的每一个组数为x的子集都像这个物体在x维的一个不同方面的投影。对于一个y组的方案,会产生C(y,x)个投影。那么将这些投影减去,就可以得到”正好x组“的方案数。
因此可以倒着求,求到x的时候,g[x+1]、g[x+2]…g[n]都已经是“正好”的方案数了,于是就可以得到答案了。
由于我智商有限,网上各路神犇的题解理解起来实在是绞尽脑汁,希望我的这篇文章能更加通俗生动地帮助有同样境遇的同学吧,写得不好或者不严谨请见谅。
组合数忘取模WA了3次233333

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mob=1000000009;
ll f[2001][2001],C[2001][2001],ans[2001],suf[2001]={1};
int a[2001],b[2001],cnt[2001];
int n,k;
int main()
{
    scanf("%d%d",&n,&k);
    if((n+k)&1) return puts("0"),0;
    k=n+k>>1;
    for(int i=1;i<=n;++i) scanf("%d",a+i);sort(a+1,a+n+1);
    for(int i=1;i<=n;++i) scanf("%d",b+i);sort(b+1,b+n+1);
    for(int i=1,now=1;i<=n;++i)
    {
        while(now<=n&&b[now]<a[i]) ++now;
        cnt[i]=now-1;
    }
    f[0][0]=1;
    for(int i=1;i<=n;++i)
    {
        f[i][0]=1;
        for(int j=1;j<=n&&f[i-1][j-1];++j)
        f[i][j]=(f[i-1][j]+f[i-1][j-1]*(j<=cnt[i]?cnt[i]-j+1:0))%mob;
    }
    for(int i=0;i<=n;++i)
    {
        C[i][0]=1;
        for(int j=1;j<=i;++j)
        C[i][j]=(C[i-1][j]+C[i-1][j-1])%mob;
    }
    for(int i=1;i<=n;++i)
        suf[i]=suf[i-1]*i%mob;
    for(int i=n;i>=k;--i)
    {
        ans[i]=f[n][i]*suf[n-i]%mob;
        if(!ans[i]) continue;
        for(int j=i+1;j<=n;++j)
        {
            ans[i]-=ans[j]*C[j][i];
            if(ans[i]<0) ans[i]=ans[i]%mob+mob;
        }
    }
    printf("%lld\n",ans[k]%mob);
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

[BZOJ3622]已经没有什么好害怕的了(dp+容斥原理+组合数学)

题目描述传送门题解首先判断是否有解,也就是(n+k)/2 mod 2=0 这样的话也就相当于糖比药大的正好有(n+k)/2组 然后剩下的和BZOJ2024就一样了 dpf(i,j)表示前i个糖选...

bzoj 3622: 已经没有什么好害怕的了 dp+容斥原理

题意给出两个长度为n的序列,满足任意两个元素互不相同。现在要拿第一个数列的数和第二个数列的数两两匹配,设第一个数列的数大于第二个数列的数的组数为s,问有多少种匹配方案使得s-(n-s)=k nb[j...

BZOJ 3622(已经没有什么好害怕的了-Dp+容斥原理)

3622: 已经没有什么好害怕的了 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 7  Solved: 6 [Submit][Status] ...

【BZOJ3622】已经没有什么好害怕的了,两次DP

传送门 写在前面:sunshine爷的模拟题之一,妈妈以后只要是模拟赛我再也不用万能库了啊啊啊啊(你们懂得) 思路: 1.首先想到(n-k) mod 2==1与k...

[bzoj3622]已经没有什么好害怕的了

3622: 已经没有什么好害怕的了Time Limit: 10 Sec Memory Limit: 256 MB Submit: 197 Solved: 113 [Submit][Status...

BZOJ3622: 已经没有什么好害怕的了

Description Input Output Sample Input 4 2 5 35 15 45 40 20 10 30 Sample Output 4 HINT ...

BZOJ 3622 已经没有什么好害怕的了 动态规划+容斥原理

题目大意:给定两个长度为n个序列,保证这2n个数字两两不同,求有多少匹配满足a[i]>b[i]的数对数比a[i] もう何も怖くない 题解:http://www.cnblogs.com/dyll...
  • PoPoQQQ
  • PoPoQQQ
  • 2015年03月21日 10:48
  • 2525

BZOJ3622 已经没有什么好害怕的了

KuribohG神犇说过,看到计数想容斥 先把两个数组排序,然后f[i][j]表示从a数组中的前i个里选j个,b数组里任选j个,满足选出来的数两两配对a里的都比b里的大的方案数,因为a数组有序了,所以...

【BZOJ3622】已经没有什么好害怕的了 动态规划+容斥原理

题解: 首先我们给AA数组(糖果)和BB数组(药片)从小到大排个序。 lastilast_i 表示一个极大值 xx 使得 BxAiB_x 。 f(i,j)f(i,j) 表示枚举到第 AiA_i ...
  • Vmurder
  • Vmurder
  • 2015年04月02日 19:20
  • 1579

[BZOJ 3622]已经没有什么好害怕的了

容斥原理
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:BZOJ3622: 已经没有什么好害怕的了 DP
举报原因:
原因补充:

(最多只允许输入30个字)