您的位置:首页 > 其它

【JZOJ 5427】【NOIP2017提高A组集训10.25】吃草

2017-10-26 17:30 706 查看

Description

后院总共有n片草坪,第i片草坪投影到数轴上,是一段l[i]到r[i]的闭区间,保证l[i]+r[i]是偶数,l[i]<=r[i]。

Sullivan可以在整点上放0v0来把草吃掉(于是0v0变成了0π0)。如果第i片草坪覆盖了x点上的0π0(l[i]<=x<=r[i]),那么这只0π0就可以吃掉这片草坪里的草。每一片草坪的草需要且只能被一只0π0吃掉。如果一片草坪覆盖了多只0π0,Sullivan可以选择任意一只去吃草。

但是,0π0吃草是有代价的,对于第i片草坪,假如吃草的0π0位于x点上,代价为abs((x-l[i])-(r[i]-x)),即0π0到草坪两端距离之差。

现在,Sullivan想知道:

1.最少需要放几只0v0?

2.在放最少只数的0v0情况下,代价最小是多少?

Solution

如果只要求至少放多少个,贪心即可,每次找到最左的一个l,放下去。

怎么求方案呢,

考虑不用贪心,用DP,

设fi表示在i放,

O(n2)的转移显然,只要合法均可以转移,

考虑怎么求最小的代价,

原式:|li+ri−2x|

因为数据保证li+ri为偶数,设ai=(li+ri)/2

所以:2|ai−x|

因为要保证有解,所以求代价不用考虑是否合法,最小的情况一定合法,

如果从j转移到i,那么代价怎么计算:

mid=(i+j)/2,那么对于ak(j<ak<i),在mid左边的就去j,右边的就去i,

计算答案就记录俩前缀和即可,

这样的复杂度是O(n2)的(其实可以过2333)

进一步考虑发现,这个是具有决策单调性的,

那么就可以优化到O(n)了,

Code

//fi表示代价,gi表示最少放多少个

#include <cstdio>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define min(q,w) ((q)>(w)?(w):(q))
#define JS(i,j,mid) (f[j]+(b[mid][1]-b[j][1]-(b[mid][0]-b[j][0])*(j))+(-b[i][1]+b[mid][1]+(b[i][0]-b[mid][0])*(i)))
using namespace std;
typedef long long LL;
const int N=300500;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,mxl,ans;
LL ans1;
struct qqww
{
int l,r;
}a
;
int b
[2];
LL f
;
int g
;
bool PX(qqww q,qqww w){return q.r<w.r;}
int main()
{
int w,_,lst;
read(n),read(_);
fo(i,1,n)read(a[i].l),read(a[i].r);
sort(a+1,a+1+n,PX);
fo(i,1,n)b[(a[i].l+a[i].r)>>1][0]++;
fo(i,1,a
.r)b[i][1]=b[i-1][1]+b[i][0]*i,b[i][0]+=b[i-1][0];
mxl=w=lst=0;
fo(i,1,a
.r)
{
f[i]=1e11;g[i]=1e9;
for(;w<=n&&a[w].r<i;w++)mxl=max(mxl,a[w].l);
if(lst<mxl)lst=mxl;
fo(j,lst,i-1)if(g[i]>=g[j]+1)
{
int mid=(j+i)>>1;
if(g[i]>g[j]+1)g[i]=g[j]+1,f[i]=1e11,lst=j;
LL t=JS(i,j,mid);
f[i]=min(f[i],t);
}
else break;//决策单调优化
}
for(;w<=n;w++)mxl=max(mxl,a[w].l);
ans=1e9;
fo(i,mxl,a
.r)ans=min(ans,g[i]);
printf("%d\n",ans);
ans1=1e11;
fo(i,mxl,a
.r)if(ans==g[i])ans1=min(ans1,f[i]+b[a
.r][1]-b[i][1]-(b[a
.r][0]-b[i][0])*i);
if(_)printf("%lld\n",2LL*ans1);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: