zoukankan      html  css  js  c++  java
  • [Codeforces 626F]Group Projects

    题目大意:

    给定(n)个数(a[1]sim a[n]),让你把它分为若干个集合,使每个集合内最大值与最小值的差的总和不超过(K)。问总方案数。

    解题思路:

    一道很神的dp题。

    首先将数进行排序,然后将这些数扔数轴上,则集合价值相当于在数轴上覆盖这些点所用的最短线段的长度(当然长度可以为0)。

    考虑dp,设(f[i][j][k])表示考虑了前(i)个点,目前还未确定右端点的集合还有(j)条,目前的总价值为(k),则

    不论如何,新加进(a[i+1]-a[i])这条线段,对(j)个集合均有影响,因此会增加价值为((a[i+1]-a[i]) imes j),设其为(t)。

    转移分四种情况:

    1. 该点单独成一个集合,则(j)不变,仅有1种情况,(f[i+1][j][k+t]+=f[i][j][k]);
    2. 该点作为某个集合的中间元素,则(j)也不变,对于(j)个集合都有可能,因此(f[i+1][j][k+t]+=f[i][j][k] imes j);
    3. 该点作为一个集合的起点,则集合数多了1,仅有1种情况,(f[i+1][j+1][k+t]+=f[i][j][k]);
    4. 该点作为一个集合的终点,则集合数少了1,对于(j)个集合都有可能,因此(f[i+1][j−1][k+t]+=f[i][j][k] imes j)。

    答案为(sumlimits_{i=0}^K f[n][0][i])。

    时空复杂度均为(O(n^2K)),空间复杂度可以用滚动数组优化到(O(nK))。

    C++ Code:

    #include<bits/stdc++.h>
    using namespace std;
    const int md=1e9+7;
    int n,K,cur,a[201],dp[2][201][1001];
    int main(){
    	ios::sync_with_stdio(0),cin.tie(0);
    	cin>>n>>K;
    	for(int i=1;i<=n;++i)cin>>a[i];
    	sort(a+1,a+n+1);
    	dp[1][1][0]=dp[1][0][0]=cur=1;
    	for(int i=1;i<n;++i){
    		const int otr=cur;
    		memset(dp[cur^=1],0,sizeof dp[0]);
    		for(int j=0;j<=i;++j){
    			const int t=j*(a[i+1]-a[i]);
    			for(int k=0;k+t<=K;++k){
    				dp[cur][j][k+t]=(dp[cur][j][k+t]+dp[otr][j][k]*(j+1ll)%md)%md;
    				if(j<n)dp[cur][j+1][k+t]=(dp[cur][j+1][k+t]+dp[otr][j][k])%md;
    				if(j)dp[cur][j-1][k+t]=(dp[cur][j-1][k+t]+1ll*dp[otr][j][k]*j%md)%md;
    			}
    		}
    	}
    	int ans=0;
    	for(int i=0;i<=K;++i)
    	ans=(1ll*dp[cur][0][i]+ans)%md;
    	cout<<ans<<endl;
    	return 0;
    }
  • 相关阅读:
    C#单例模式的三种写法
    【TFS】增加组员,以及用户权限分配
    Mongodb实用网址记录
    关于JS 对象与JSON对象
    多线程操作
    检测到有潜在危险的 Request.Form 值
    JavaScript 【正则表达式验证数字代码】
    【SQL】大杂烩
    IE 中创建 子窗口 传值 与接收值 【window.showModalDialog】
    UITabbarView Tabbar
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/9348255.html
Copyright © 2011-2022 走看看