Codeforces 626F Group Projects (DP)

16 篇文章 0 订阅

官方题解很详细

This is a dynamic programming problem. Notice that the total imbalance of the groups only depends on which students are the maximum in each group and which are the minimum in each group. We thus can think of groups as intervals bounded by the minimum and maximum student. Moreover, the total imbalance is the sum over all unit ranges of the number of intervals covering that range. We can use this formula to do our DP.

If we sort the students in increasing size, DP state is as follows: the number of students processed so far, the number of g groups which are currently “open” (have a minimum but no maximum), and the total imbalance k so far. For each student, we first add the appropriate value to the total imbalance (g times the distance to the previous student), and then either put the student in his own group (doesn’t change g), start a new group (increment g), add the student to one of the g groups (doesn’t change g), or close one of the g groups (decrement g).

Runtime: O(n2k)


[code]:

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const LL MOD = 1e9+7;

int n,m,a[205];
LL dp[2][205][1005];

void sol(){
    int i,j,k,k_,cr,nt;
    LL val;
    dp[0][0][0] = 1;
    for(i = 0;i < n;i++){
        cr = i&1,nt = (i+1)&1;
        for(j = 0;j <= n;j++){
            for(k = 0;k <= m;k++){
                dp[nt][j][k] = 0;
            }
        }
        for(j = 0;j <= n;j++){
            for(k = 0;k <= m;k++){
                val = dp[cr][j][k];
                k_ = k + j*(a[i+1]-a[i]);
                if(val==0||k_>m) continue;
                dp[nt][j+1][k_] = (dp[nt][j+1][k_]+val)%MOD;
                dp[nt][j][k_] = (dp[nt][j][k_]+(j+1)*val)%MOD;
                if(j) dp[nt][j-1][k_] = (dp[nt][j-1][k_]+j*val)%MOD;
            }
        }
    }
    LL ans = 0;
    for(k = 0;k <= m;k++) ans = (ans + dp[n&1][0][k])%MOD;
    printf("%I64d\n",(ans+MOD)%MOD);
}

int main(){
    int i,j,k;
    scanf("%d%d",&n,&m);
    for(i = 1;i <= n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    sol();
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值