pku 3017 Cut the Sequence(贪心不是可以滥用的。。)

按着题目分类往下做,做到这一题的时候,上面说是要加数据结构的优化。

不过我随便想想,发现个贪心策略,可以把复杂度降很低。

我当时想的贪心策略是:假设num[i]...num[i]是一段,如果num[i]+...num[j]+num[j+1]<=M,则把num[j+1]直接加到前面一段上去。其他的部分按照常规DP。

我就按照这个思路写,提交后无限WA。在网上找了个正确的程序来手工对拍,跑了n组随机数据答案都是一样的,但只要一提交就是WA。后来,我不仅打印答案,还把中间数据全都给打印了出来,才终于找到了问题。之前那个贪心是错误的,还要加上一个限制条件。

假设num[i]...num[i]是一段,并且num[i]+...num[j]+num[j+1]<=M

如果 max(num[i]...num[j])>=num[j+1] ,则把num[j+1]直接加到前面一段上去。

否则重新搜索该段的起始节点,可以直接从i开始往前搜索。

 

没有加什么数据结构优化,跑390ms,勉强凑合。

 

#include <iostream> #define _clr(a,b) memset(a,b,sizeof(a)) template<class T> void get_max(T& a,T b) { if(a<b) a=b;} using namespace std; __int64 num[100005],sum[100005],M; const __int64 INF=200000000000LL; int N; struct node { __int64 max; __int64 ans; int p; }nodes[100005]; int main() { bool ok=true; scanf("%d%I64d",&N,&M); sum[0]=0; for(int i=1;i<=N;i++) { scanf("%I64d",&num[i]); sum[i]=sum[i-1]+num[i]; if(num[i]>M) ok=false; } if(ok) { nodes[0].ans=0; nodes[0].max=0; nodes[1].ans=num[1]; nodes[1].max=num[1]; nodes[1].p=0; for(int i=2;i<=N;i++) { if(sum[i]-sum[nodes[i-1].p]<=M) { if(num[i]>nodes[i-1].max) { __int64 max_num=num[i]; nodes[i].ans=INF; for(int j=nodes[i-1].p+1;j>0&∑[i]-sum[j-1]<=M;j--) { get_max(max_num,num[j]); if(nodes[j-1].ans+max_num<nodes[i].ans) { nodes[i].ans=nodes[j-1].ans+max_num; nodes[i].max=max_num; nodes[i].p=j-1; } } } else { nodes[i].max=nodes[i-1].max; nodes[i].ans=nodes[i-1].ans; nodes[i].p=nodes[i-1].p; } } else { __int64 max_num=num[i]; nodes[i].max=num[i]; nodes[i].ans=nodes[i-1].ans+num[i]; nodes[i].p=i-1; for(int j=i-1;sum[i]-sum[j-1]<=M;j--) { get_max(max_num,num[j]); if(nodes[j-1].ans+max_num<nodes[i].ans) { nodes[i].max=max_num; nodes[i].ans=nodes[j-1].ans+nodes[i].max; nodes[i].p=j-1; } } } } printf("%I64d/n",nodes[N].ans); } else printf("-1/n"); return 0; }

你可能感兴趣的:(pku 3017 Cut the Sequence(贪心不是可以滥用的。。))