Description
New Orleans家的后院有很多片草坪,Sullivan负责清理过高的草。但是,Sullivan还有很多家务要干,于是,她想到了一个好方法。
后院总共有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情况下,代价最小是多少?
Input
第一行两个正整数n,t。
第二行到第n+1行,第i+1行两个正整数l[i],r[i]。
Output
第一行一个非负整数,为最小的0v0数量。
如果t=0,没有第二行输出;如果t=1,第二行输出在放最少只数的0v0情况的最小代价。
Sample Input
3 1
1 11
2 4
5 7
Sample Output
2
0
Data Constraint
20% n,l[i],r[i]<=3000 t=0
30% n,l[i],r[i]<=300000 t=0
20% n,l[i],r[i]<=3000 t=1
30% n,l[i],r[i]<=300000 t=1
Hint
在3上与6上各放一只0v0即可
题解
对于第一个问题是可以很轻松地解决,
用贪心的思想,就是按照端点来排序,
能放在同一个就放在同一个集合里面。
对于第二个问题,
其实到两个端点的距离差只有这个区间的中间点有个,
所有,对于每一个区间都只保留它的中间点。
设fi表示在第i个点放了0v0,而且在中间点i前面的都处理完了的最小代价。
转移:
枚举一个j,mid=(i+j)/2.
如果中间点在[j,mid]里面,很显然用放在j的那只0v0,
在(mid,i)里面的,就用在i的那一只来吃。
code
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 3000003
#define db double
#define P putchar
#define G getchar
#define mo 998244353
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
ll min(ll a,ll b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
void writeln(ll x){write(x);P('\n');}
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
struct node
{
int l,r;
}a[N];
ll f[N],sum[N],g1[N],g2[N],s;
int n,t,ans,mx,m,g[N],x;
bool cmp(node a,node b){return a.r<b.r;}
int get(int x,int y,int mid)
{
ll s=0;
if(x!=0)s=g1[mid]-g1[x]-(sum[mid]-sum[x])*x;else mid=0;
s+=g2[mid+1]-g2[y]-(sum[y-1]-sum[mid])*(m-y+1);
return s;
}
int main()
{
freopen("grass.in","r",stdin);
freopen("grass.out","w",stdout);
memset(f,127,sizeof(f));
memset(g,127,sizeof(g));
read(n);read(t);
for(int i=1;i<=n;i++)
read(a[i].l),read(a[i].r),m=max(m,a[i].r),sum[(a[i].l+a[i].r)>>1]++;
for(int i=m;i;i--)
g2[i]=g2[i+1]+sum[i]*(m-i+1);
for(int i=1;i<=m;i++)
g1[i]=sum[i]*i+g1[i-1],sum[i]+=sum[i-1];
sort(a+1,a+1+n,cmp);
x=1;f[0]=g[0]=0;
for(int i=1;i<=m;i++)
{
for(;x<=n && a[x].r<i;x++)mx=max(mx,a[x].l);
for(int j=mx;j<i;j++)
if(g[j]+1<=g[i])
{
if(g[i]!=g[j]+1)g[i]=g[j]+1,f[i]=9223372036854775807;
f[i]=min(f[i],f[j]+get(j,i,(i+j)>>1));
}
}
for(;x<=n;x++)mx=max(mx,a[x].l);
ans=n;
for(int i=mx;i<=m;i++)
ans=min(ans,g[i]);
writeln(ans);
if(t==1)
{
s=9223372036854775807;
for(int i=mx;i<=m;i++)
if(ans==g[i])s=min(f[i]+get(i,m,m),s);
writeln(2*s);
}
}