zoukankan      html  css  js  c++  java
  • Acwing P277 饼干 题解

    每日一题 day20 打卡

    Analysis

    线型动态规划

    读入每个人的贪婪度之后,对其按照从大到小的顺序排序,定义状态f[i][j]为前i个人(排序后)分j个饼干的答案,那么答案为f[n][m],考虑状态转移方程。

    1、若给第i个人的饼干数大于1 ,那么我们将这i个人的饼干数都减1(总共减n),他们的怨气值是不会改变的,因而这种情况下,f[i][j]=f[i][j-i].

    2、若给第i个人的饼干数等于1,那么我们枚举一个k(0≤k<i),表示从k之后一直到i所有的人的饼干数都是1,那么f[i][j]=f[k][j-(i-k)]+k*∑g[c[p]]    (k<p<=i).

    我们先预处理出g数组的前缀和,即可实现O(n)的转移。

    综上,我们在两种决策中取最优即可。另外,本题要求输出方案,我们只需在状态转移时记录每个状态的前驱即可。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define int long long
     6 #define maxn 30+10
     7 #define maxm 5000+10
     8 using namespace std;
     9 inline int read() 
    10 {
    11     int x=0;
    12     bool f=1;
    13     char c=getchar();
    14     for(; !isdigit(c); c=getchar()) if(c=='-') f=0;
    15     for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+c-'0';
    16     if(f) return x;
    17     return 0-x;
    18 }
    19 inline void write(int x)
    20 {
    21     if(x<0){putchar('-');x=-x;}
    22     if(x>9)write(x/10);
    23     putchar(x%10+'0');
    24 }
    25 int n,m;
    26 int g[maxn],num[maxn],sum[maxn],ans[maxn];
    27 int a[maxn][maxm],b[maxn][maxm],dp[maxn][maxm];
    28 inline bool cmp(int x,int y)
    29 {
    30     return g[x]>g[y];
    31 }
    32 inline void fig(int x,int y)
    33 {
    34     if(!x) return;
    35     fig(a[x][y],b[x][y]);
    36     if(a[x][y]==x) 
    37     {
    38         for(int i=1;i<=x;i++) ans[num[i]]++;
    39     }
    40 }
    41 signed main()
    42 {
    43     memset(dp,127,sizeof(dp));
    44     n=read();m=read();
    45     for(int i=1;i<=n;i++)
    46     {
    47         g[i]=read();
    48         num[i]=i;
    49     } 
    50     sort(num+1,num+n+1,cmp);
    51     for(int i=1;i<=n;i++) ans[num[i]]=1;
    52     for(int i=1;i<=n;i++) sum[i]=sum[i-1]+g[num[i]];
    53     dp[0][0]=0;
    54     for(int i=1;i<=n;i++)
    55     {
    56         for(int j=i;j<=m;j++)
    57         {
    58             dp[i][j]=dp[i][j-i];
    59             a[i][j]=i;
    60             b[i][j]=j-i;
    61             for(int k=0;k<i;k++)
    62             {
    63                 if(dp[i][j]>dp[k][j-(i-k)]+k*(sum[i]-sum[k]))
    64                 {
    65                     dp[i][j]=dp[k][j-(i-k)]+k*(sum[i]-sum[k]);
    66                     a[i][j]=k;
    67                     b[i][j]=j-(i-k);
    68                 }
    69             }
    70         }
    71     }
    72     write(dp[n][m]);
    73     printf("
    ");
    74     fig(n,m);
    75     for(int i=1;i<=n;i++)
    76     {
    77         write(ans[i]);
    78         printf(" ");
    79     }
    80     return 0;
    81 }

    请各位大佬斧正(反正我不认识斧正是什么意思)

  • 相关阅读:
    c语言中srand和rand函数 生成随机数总结
    枚举类型
    VS2008快捷键使用技巧
    PV实现同步
    PV操作(深入显出)
    数字在排序数组中出现的次数
    两个链表的第一个公共结点
    数组中的逆序对
    第一个只出现一次的字符位置
    丑数
  • 原文地址:https://www.cnblogs.com/handsome-zyc/p/11586838.html
Copyright © 2011-2022 走看看