-
P5569 【SDOI2008】 石子合并(黑科技)
#$Solution$
当$n$在$100$左右时,直接$O(n^3)$区间$DP$
当$n$在$40000$左右时,需要用贪心算法:**加西亚-瓦克斯算法**($Garsia Wachs$)
注:这个方法仅求石子合并的最小答案
这是大概的流程
![](https://img2018.cnblogs.com/blog/1564177/201910/1564177-20191023084425774-478020738.png)
这是关于$Garsia Wachs$算法的正确性证明:[传送门](https://blog.csdn.net/nameofcsdn/article/details/79682936)
时间复杂度最坏为$O(n^2)$,但是基本跑不满,数据随机的话$n=40000$能搞过去
代码使用链表实现,方便删除和插入操作,边界什么的比较麻烦,一定要注意,可以看看代码注释
#$Code$
```
#include
#include
#include
#include
#define re register
#define maxn 1000010
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll ans,tmp;
int l[maxn],r[maxn],v[maxn],n,a[maxn],cnt,num;
int main()
{
n=read();
for(re int i=1;i<=n;++i)
{
a[i]=read();
v[i]=a[i],l[i]=i-1,r[i]=i+1;
}
v[0]=v[n+1]=INF;//赋为无穷大作为边界,保证所有删除插入都在边界内完成
r[0]=1,l[0]=-1;//这里要赋成-1,否则到了0,l[0]=0会一直死循环
l[n+1]=n,r[n+1]=0;
cnt=n;
num=n+1;//从n+2开始编号
while(cnt>1)//=1的时候跳出就行了
{
cnt--;
int now=0;
while(r[r[now]]!=0)//不要写>=n+1,因为新的编号是>=n+1的,往右找是0就到了真是的边界,退出
{
if(v[r[r[now]]]>=v[now]) break;
now=r[now];
}
tmp=v[now]+v[r[now]];
ans+=tmp;统计答案
r[l[now]]=r[r[now]];
l[r[r[now]]]=l[now];//删除操作,删除两个
now=l[now];
while(now>=0)//这里可以写>=0,往左是-1就代表到边界了
{
if(v[now]>tmp) break;
now=l[now];
}
num++;
l[num]=now,r[num]=r[now],v[num]=tmp;
r[now]=num;//插入操作
l[r[num]]=num;
}
printf("%d
",ans);
return 0;
}
```
-
相关阅读:
2017(秋)软工作业: (2)硬币游戏—— 代码分析与改进
软工作业(1)课程学习热身
用户体验分析:以 “师路南通网站” 为例
用户体验分析: 以 “南通大学教务管理系统微信公众号” 为例
软件工程第二次作业:硬币游戏—— 代码分析与改进
自我介绍
用户体验分析---以师路南通为例
用户体验分析---七八点照相馆
硬币游戏—— 代码分析与改进
About me
-
原文地址:https://www.cnblogs.com/Liuz8848/p/11723914.html
Copyright © 2020-2023
润新知