b276: 4和7 ---------DP

来源:互联网 发布:英雄联盟显示网络异常 编辑:程序博客网 时间:2024/04/29 18:47

原题地址

DP妥妥的,看数据规模,首先需要离散化,其次转移的时间复杂度不能超过O(n^2),应当是O(n)左右

Point.1 某个规律

因为4和7互质,所以必然存在某个值k,使大于k的任意数都能分解为4和7的组合,手动模拟出这个数是18。理论上讲扩欧应该能够算出来。。。

Point.2 离散化

由于格子太多显然不能作为数组下标,但药堆数不大,所以读入时先储存下药粒数和位置信息,按位置排序。结合point.1,相邻两堆药之间的距离大于18时,实际上和等于18没差,因为后一个状态肯定能由前一个转移过来,所以重构格子序列,把所有大于18的间隔缩成18,这样就把格子编号缩到1800000范围内,就可以作为下标实现转移了。

Point.3 初始化

初始时f[i]一定要设成极小值,保证每次更新ans的f[i]都是已被更新过的,否则结果会比正解大;f[0]设为0,不然绝壁输出负数。

Point.4 转移

枚举每个位置(离散化后),f[i-4],f[i-7],f[i]取最大值。

参考代码:

#include<iostream>#include<algorithm>#include<cmath>#include<cstring>using namespace std;long long  a[1800005],f[1800005];int n;long long m,ans,x,y;struct mc{long long num,pos;bool operator <(const mc b) const{return pos<b.pos;}}e[100005],p[100005];void dp(){long long st=0;for (int i=1;i<=n;i++)scanf("%d%lld",&e[i].num,&e[i].pos);sort(e+1,e+n+1);long long sx=0;e[0].num=0;e[0].pos=0;for (int i=1;i<=n;i++){if (!(e[i].pos-e[i-1].pos)){a[st]+=e[i].num;continue;}if (e[i].pos-e[i-1].pos>=18){st+=18;a[st]=e[i].num;}else{st+=e[i].pos-e[i-1].pos;a[st]=e[i].num;}}for (int i=1;i<=st;i++){f[i]=-210000000;if (i>=4)    f[i]=max(f[i-4]+a[i],f[i]);if (i>=7)    f[i]=max(f[i-7]+a[i],f[i]);if (ans<f[i]) ans=f[i];}return;}int main(){freopen("hop.in","r",stdin);freopen("hop.out","w",stdout);scanf("%d%lld",&n,&m);memset(a,0,sizeof(a));memset(f,0,sizeof(f));long long sy=0;dp();printf("%lld",ans);return 0;}


0 0
原创粉丝点击