zoukankan      html  css  js  c++  java
  • AcWing277. 饼干

    题目链接

    大致题意

    (m)块饼干,(n)个人,每个人都有一个贪婪度,第(i)个人的贪婪度为(g_i),如果有(a_i)个人拿到的饼干数比第(i)个人多,那么他就会产生(g_i×a_i)的怨气,求一种排列方式,使得每个人至少分到一块饼干且怨气和最小

    (n≤30,n≤m≤5000)

    分析

    发现这个贡献计算是有后效性的,不太好搞

    先来尝试猜个结论:越贪的人吃越多的饼干,用邻项交换易证。这样每个人分到的饼干数就是单调不上升的了

    也就是说,要计算第(i)个人的贡献,我们只需要知道第(i)个人前面有几个人和他分到的饼干数相等,一个比较NAIVE的想法是设(f(i,j,k))表示在前(i)个人中,一共分了(j)块饼干,第(i)个人分到(k)块时的最小怨气值和

    转移也比较显然,枚举前面有几个人和他分到的饼干数相等:

    (f(i,j,k) = minegin{cases}min(f(i-1,j-k,p)+g_i×(i-1))&{j-k≥p×(i-1),p>k})\min(f(i-p,j-p×k,k)+sum_{b=i-p+1}^ig_b×(i-p-1))&{j-p×k≥(i-p-1)×k}end{cases})

    时间复杂度(O(nm^3))

    数据似乎比较水(,可以拿个80pts左右的样子

    现在来考虑优化

    可以发现,我们只关心每个人分到的饼干数之间的相对大小,而不关心其具体数值,因此我们可以尝试去把前面那个状态的(k)维度去掉

    (f(i,j))表示在前(i)个人中共分了(j)块饼干的最小怨气值和

    如果第(i)个人分到的饼干数不为(1),(i)个人共分到(j)块饼干等价于每人少分一块饼干,既(f(i,j-i)),因为每个人拿到的饼干数之间的相对大小没有变,总贡献也不会变

    如果第(i)个人分到的饼干数为(1),那么就可以枚举他前面有多少个人分到的饼干数也为(1)

    转移方程(:)

    $f(i,j) = minegin{cases}f(i,j-i)&{j≥i}\min(f(k,j-(i-k))+sum_{x=k+1}^ig_i×k)&{j≥i-k}end{cases}$

    (code)

    //xcxc82
    /*
    80pts
    memset(f,0x3f,sizeof(f));
    memset(f[1],0,sizeof(f[1]));
      for(int i=2;i<=n;i++){
        for(int j=1;j<=m;j++){
          for(int k=1;k<j;k++){
        	for(int p=k+1;p<=j;p++){
        		if(j-k<p*(i-1)||j<k) continue;
        		f[i][j][k] = min(f[i][j][k],f[i-1][j-k][p]+g[i]*(i-1));
    	}
    		for(int p=1;p<=i-1;p++){//注意要特判p=i-1,j-p×k!=k的情况
    			if(j-p*k<(i-p-1)*k||j<p*k||(p==i-1&&j-p*k!=k)) continue;
    			 f[i][j][k] = min(f[i][j][k],f[i-p][j-p*k][k]+(i-p-1)*(sum[i]-sum[i-p]));
    	    }
    	}
        }
    }
    */
    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 5010;
    int sum[MAXN],n,m,f[MAXN/100][MAXN];
    int l1[MAXN/100][MAXN],l2[MAXN/100][MAXN],ans[MAXN/100];
    struct cookie{
    	int g,ind;
    }a[MAXN];
    bool cmp(cookie x,cookie y){
    	return x.g>y.g;
    }
    int SUM(int i,int j){
        return sum[j] - sum[i-1];	
    }
    inline int read(){
    	int X=0; bool flag=1; char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
    	while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
    	if(flag) return X;return ~(X-1);
    }
    void print(int i,int j){
    	if(i==0) return;
    	print(l1[i][j],l2[i][j]);
    	if(i==l1[i][j]){
    		for(int x=1;x<=i;x++) ans[a[x].ind]++;
    	}
    	else for(int x=l1[i][j]+1;x<=i;x++) ans[a[x].ind] = 1;
    }
    int main(){
    	n = read(),m = read();
    	for(int i=1;i<=n;i++) a[i].g = read(),a[i].ind = i;
    	sort(a+1,a+n+1,cmp); 
    	for(int i=1;i<=n;i++) sum[i] = sum[i-1]+a[i].g;
    	memset(f,0x3f,sizeof(f));
        f[0][0] = 0;
        for(int i=1;i<=n;i++){
        	for(int j=i;j<=m;j++){
        		for(int k=0;k<i;k++){
        			if(f[k][j-(i-k)]+k*SUM(k+1,i)<f[i][j]){
        				f[i][j] = f[k][j-(i-k)]+k*SUM(k+1,i);
        				l1[i][j] = k,l2[i][j] = j-(i-k);
    				}
    			}
    			if(f[i][j-i]<f[i][j]){
    				f[i][j] = f[i][j-i];
    				l1[i][j] = i,l2[i][j] = j-i;
    			}
    		}
    	}
    	printf("%d
    ",f[n][m]);
    	print(n,m);
    	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
       return 0;
    }
    
    
    
    
    
    
    
  • 相关阅读:
    eclipse 远程debug tomcat web项目
    阿里巴巴fastjson的使用
    STS 3.6.4 SpringMVC 4.1.6 Hibernate 4.3.8 MySQL
    Ubuntu su 认证失败
    mysql mha高可用架构的安装
    Swift开发教程--关于Existing instance variable &#39;_delegate&#39;...的解决的方法
    设计模式-适配器模式(Go语言描写叙述)
    Xcode6.3 怎样使用Leaks查看内存泄露
    java中的subString具体解释及应用
    出走三上海篇
  • 原文地址:https://www.cnblogs.com/xcxc82/p/14284452.html
Copyright © 2011-2022 走看看