• 【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
  • 相关阅读:
    数据导入和导出
    用户登陆案例
    SQLHelper
    把连接数据库的字符串放在配置文件中
    访问数据库
    SQL语句
    Django Tornado Flask
    Python 的协程
    面试 Better Call Soul
    mklink 解决VScode 扩展...Google迁移到 windows D盘
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8721640.html
Copyright © 2020-2023  润新知