zoukankan      html  css  js  c++  java
  • 【CodeForces】626 F. Group Projects 动态规划

    【题目】F. Group Projects

    【题意】给定k和n个数字ai,要求分成若干集合使得每个集合内部极差的总和不超过k的方案数。n<=200,m<=1000,1<=ai<=500。

    【算法】动态规划

    【题解】每个集合的最小值和最大值非常重要,将序列从小到大排序后,每个集合可以视为最小值到最大值的一条线段。

    设$f[i][j][k]$表示前i个数,当前有j条线段没有结束,总和为k的方案数。

    转移的关键在于集合权值的拆分,转化为算每个数的贡献。数字a[i+1]的贡献就是覆盖的线段条数,即$t=(a[i+1]-a[i])*j$,分类讨论:

    是一条线段的起点和终点

    $$f[i+1][j][k+t]+=f[i][j][k]$$

    即不是起点,又不是终点

    $$f[i+1][j][k+t]+=f[i][j][k]*j$$

    是起点,不是终点

    $$f[i+1][j+1][k+t]+=f[i][j][k]$$

    是终点,不是起点

    $$f[i+1][j-1][k+t]+=f[i][j][k]*j$$

    复杂度O(n^2*m)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=210,K=1010,MOD=1e9+7;
    int n,m,a[N],f[N][N][K];
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        f[1][1][0]=f[1][0][0]=1;
        for(int i=1;i<=n;i++)
            for(int j=0;j<=n;j++){
                int t=(a[i+1]-a[i])*j;
                for(int k=0;k+t<=m;k++){
                    int x=f[i][j][k];
                    f[i+1][j][k+t]=(f[i+1][j][k+t]+1ll*x*(j+1))%MOD;
                    f[i+1][j+1][k+t]=(f[i+1][j+1][k+t]+x)%MOD;
                    if(j)f[i+1][j-1][k+t]=(f[i+1][j-1][k+t]+1ll*x*j)%MOD;
                }
            }
        int ans=0;
        for(int i=0;i<=m;i++)ans=(ans+f[n][0][i])%MOD;
        printf("%d",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    HDU 6071
    HDU 6073
    HDU 2124 Repair the Wall(贪心)
    HDU 2037 今年暑假不AC(贪心)
    HDU 1257 最少拦截系统(贪心)
    HDU 1789 Doing Homework again(贪心)
    HDU 1009 FatMouse' Trade(贪心)
    HDU 2216 Game III(BFS)
    HDU 1509 Windows Message Queue(队列)
    HDU 1081 To The Max(动态规划)
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8721640.html
Copyright © 2011-2022 走看看