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("\n");
74     fig(n,m);
75     for(int i=1;i<=n;i++)
76     {
77         write(ans[i]);
78         printf(" ");
79     }
80     return 0;
81 }

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

posted @ 2019-09-25 19:24  handsome_zyc  阅读(238)  评论(0编辑  收藏  举报