zoukankan      html  css  js  c++  java
  • 【BZOJ3622】已经没什么好害怕的了 容斥原理+dp

    Description

    img

    Input

    img

    Output

    img

    Sample Input

    4 2
    5 35 15 45
    40 20 10 30

    Sample Output

    4

    HINT

    img

    输入的2*n个数字保证全不相同。

    还有输入应该是第二行是糖果,第三行是药片

    Sol

    先把两个数组排序,能够把题目的分析难度降低一些。

    然后我们求出(r[i])表示b中小于(a[i])的最靠右的位置,这样dp的时候就能够(O(1))转移了。

    (f[i][j])表示考虑了i位,至少有j个满足a>b的方案数。

    显然(f[i][j]=f[i-1][j]+f[i-1][j-1]*max(0,r[i]-j+1))

    这样的方案数是“至少”,我们需要求的是“恰好”,所以需要容斥一波。

    (g[i])表示恰好i个的方案数,那么我们的计算方法就是用全部情况减去不合法的情况。

    显然全部情况是(f[n][i]*(n-i)!),阶乘就表示剩下的可以任意选择。

    然后我们需要减去的是:(sum_{j=i+1}^{n}g[j]*C(j,i))

    这个式子的意义是:对于每个恰好是j的方案的排列中,任意选择i个数字的方案数,也就是不合法的总方案数。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,a[2005],b[2005],f[2005][2005],g[2005],d[2005]={1},c[2005][2005],r[2005],P=1e9+9;
    int main()
    {
    	scanf("%d%d",&n,&m);m=(m+n)>>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,j=1;i<=n;r[i]=j-1,i++) for(;j<=n&&b[j]<a[i];j++);
    	for(int i=0,j;i<=2000;i++) for(c[i][0]=1,j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%P;
    	for(int i=1;i<=2000;i++) d[i]=1ll*d[i-1]*i%P;
    	for(int i=0;i<=n;i++) f[i][0]=1;
    	for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) f[i][j]=(f[i-1][j]+1ll*f[i-1][j-1]*max(r[i]-j+1,0)%P)%P;
    	for(int i=n,j;i>=m;i--) for(g[i]=1ll*f[n][i]*d[n-i]%P,j=i+1;j<=n;j++) g[i]=(g[i]-1ll*c[j][i]*g[j]%P+P)%P;
    	printf("%d
    ",g[m]);
    }
    
  • 相关阅读:
    table常用功能总结
    oracle中number类型的数据使用as string 得到的值为null
    Oracle连接超时
    VS重新生成后仍然执行旧代码
    .NET 环境中使用RabbitMQ
    使用CLR Function代替T-SQL函数,优化检索效率
    SQL Server CLR 使用 C# 自定义存储过程和触发器
    OrderBy排序和IComparer的使用
    System.net.mail 使用ssl发送邮件失败
    C#利用CDO.Message发送邮件
  • 原文地址:https://www.cnblogs.com/CK6100LGEV2/p/9414949.html
Copyright © 2011-2022 走看看