Codeforces Round #422 (Div. 2) C. Hacker, pack your bags! 思维排序或二分
2017-07-17 15:08
393 查看
题目:http://codeforces.com/contest/822/problem/C
题意:给多个区间,每个区间都有一个权值,求两个长度和为x的区间的最小权值和。
思路1:像这种找两个区间的问题,对于每个区间只需考虑在他左面的或只需考虑在他右面的即可,不需要都考虑,就像区间1 区间2 和区间2 区间1 效果是一样的
维护一个need【i】表示长度为i的区间的最小权值,至于如何保证区间不交,控制一下维护顺序即可,对原区间按左端点从小到大排序,1->n遍历一遍,设当前区间左端点l,右端点r,权值c,因此长度为r-l+1,这时need【i】表示的通过所有右端点小于l的区间(也就是在此区间左边的区间)维护后的值,控制这个维护的顺序可以用优先队列实现,也可以直接排序,还有一种方法就是以右端点为索引保存这个区间,遍历即可。
优先队列写法:171ms
#include<bits/stdc++.h>
using namespace std;
struct node
{
int le,ri,cost;
bool operator < (const node u)const
{
return ri>u.ri;
}
}num[200005];
int need[200005];
int cmp(node u,node v)
{
if(u.le==v.le)
return u.ri<v.ri;
return u.le<v.le;
}
priority_queue<node>q;
4000
int main()
{
int i,n,x,l,r,c,ban;
cin>>n>>x;
for(i=0;i<n;i++)
scanf("%d %d %d",&num[i].le,&num[i].ri,&num[i].cost);
sort(num,num+n,cmp);
int minn=2e9+2;
for(i=0;i<n;i++)
{
int now=num[i].ri-num[i].le+1;
if(now>=x)
continue;
if(need[x-now])
minn=min(minn,need[x-now]+num[i].cost);
q.push(num[i]);
if(i!=n-1)
while(!q.empty())
{
node t=q.top();
if(t.ri>=num[i+1].le)
break;
q.pop();
// cout<<t.le<<" "<<t.ri<<" "<<t.cost<<endl;
if(need[t.ri-t.le+1])
need[t.ri-t.le+1]=min(need[t.ri-t.le+1],t.cost);
else
need[t.ri-t.le+1]=t.cost;
}
}
if(minn==2e9+2)
cout<<-1<<endl;
else
cout<<minn<<endl;
return 0;
}
排序写法:171ms
#include<bits/stdc++.h>
using namespace std;
struct node
{
int le,ri,cost;
}num[200005],again[200005];
int need[200005];
int cmp(node u,node v)
{
if(u.le==v.le)
return u.ri<v.ri;
return u.le<v.le;
}
int cmp2(node u,node v)
{
return u.ri<v.ri;
}
int main()
{
int i,n,x,l,r,c,ban;
cin>>n>>x;
for(i=0;i<n;i++)
scanf("%d %d %d",&num[i].le,&num[i].ri,&num[i].cost),again[i]=num[i];
sort(num,num+n,cmp);
sort(again,again+n,cmp2);
int minn=2e9+1;
int index=0;
for(i=0;i<n;i++)
{
int now=num[i].ri-num[i].le+1;
if(now>=x)
continue;
if(need[x-now])
minn=min(minn,need[x-now]+num[i].cost);
if(i!=n-1)
while(again[index].ri<num[i+1].le)
{
now=again[index].ri-again[index].le+1;
if(need[now])
need[now]=min(need[now],again[index].cost);
else
need[now]=again[index].cost;
index++;
}
}
if(minn==2e9+1)
cout<<-1<<endl;
else
cout<<minn<<endl;
return 0;
}
右端点vector记录写法:202ms(本以为这个是最优的。。。)
#include<bits/stdc++.h>
using namespace std;
struct node
{
int le,ri,cost;
}num[200005];
int need[200005];
int cmp(node u,node v)
{
if(u.le==v.le)
return u.ri<v.ri;
return u.le<v.le;
}
vector<node>again[200005];
int main()
{
int i,n,x,l,r,c,ban;
cin>>n>>x;
for(i=0;i<n;i++)
scanf("%d %d %d",&num[i].le,&num[i].ri,&num[i].cost),again[num[i].ri].push_back(num[i]);
sort(num,num+n,cmp);
int minn=2e9+1,index=0;
for(i=0;i<n;i++)
{
int now=num[i].ri-num[i].le+1;
if(now>=x)
continue;
if(need[x-now])
minn=min(minn,need[x-now]+num[i].cost);
if(i!=n-1)
for(;index<num[i+1].le;index++)
{
for(int j=0;j<again[index].size();j++)
{
now=again[index][j].ri-again[index][j].le+1;
if(need[now])
need[now]=min(need[now],again[index][j].cost);
else
need[now]=again[index][j].cost;
}
}
}
if(minn==2e9+1)
cout<<-1<<endl;
else
cout<<minn<<endl;
return 0;
}
思路2:二分。和上面思路整体相同,vector【i】记录长度为i的所有区间,遍历每个区间,在长度匹配的区间里二分找合适的,事先求一个权值最小后缀,优化一下即可。
记得上次去西安遇到一个和这个类似的题目,卡了很长时间都没出。现在又是想了半天也没有思路。。。。
题意:给多个区间,每个区间都有一个权值,求两个长度和为x的区间的最小权值和。
思路1:像这种找两个区间的问题,对于每个区间只需考虑在他左面的或只需考虑在他右面的即可,不需要都考虑,就像区间1 区间2 和区间2 区间1 效果是一样的
维护一个need【i】表示长度为i的区间的最小权值,至于如何保证区间不交,控制一下维护顺序即可,对原区间按左端点从小到大排序,1->n遍历一遍,设当前区间左端点l,右端点r,权值c,因此长度为r-l+1,这时need【i】表示的通过所有右端点小于l的区间(也就是在此区间左边的区间)维护后的值,控制这个维护的顺序可以用优先队列实现,也可以直接排序,还有一种方法就是以右端点为索引保存这个区间,遍历即可。
优先队列写法:171ms
#include<bits/stdc++.h>
using namespace std;
struct node
{
int le,ri,cost;
bool operator < (const node u)const
{
return ri>u.ri;
}
}num[200005];
int need[200005];
int cmp(node u,node v)
{
if(u.le==v.le)
return u.ri<v.ri;
return u.le<v.le;
}
priority_queue<node>q;
4000
int main()
{
int i,n,x,l,r,c,ban;
cin>>n>>x;
for(i=0;i<n;i++)
scanf("%d %d %d",&num[i].le,&num[i].ri,&num[i].cost);
sort(num,num+n,cmp);
int minn=2e9+2;
for(i=0;i<n;i++)
{
int now=num[i].ri-num[i].le+1;
if(now>=x)
continue;
if(need[x-now])
minn=min(minn,need[x-now]+num[i].cost);
q.push(num[i]);
if(i!=n-1)
while(!q.empty())
{
node t=q.top();
if(t.ri>=num[i+1].le)
break;
q.pop();
// cout<<t.le<<" "<<t.ri<<" "<<t.cost<<endl;
if(need[t.ri-t.le+1])
need[t.ri-t.le+1]=min(need[t.ri-t.le+1],t.cost);
else
need[t.ri-t.le+1]=t.cost;
}
}
if(minn==2e9+2)
cout<<-1<<endl;
else
cout<<minn<<endl;
return 0;
}
排序写法:171ms
#include<bits/stdc++.h>
using namespace std;
struct node
{
int le,ri,cost;
}num[200005],again[200005];
int need[200005];
int cmp(node u,node v)
{
if(u.le==v.le)
return u.ri<v.ri;
return u.le<v.le;
}
int cmp2(node u,node v)
{
return u.ri<v.ri;
}
int main()
{
int i,n,x,l,r,c,ban;
cin>>n>>x;
for(i=0;i<n;i++)
scanf("%d %d %d",&num[i].le,&num[i].ri,&num[i].cost),again[i]=num[i];
sort(num,num+n,cmp);
sort(again,again+n,cmp2);
int minn=2e9+1;
int index=0;
for(i=0;i<n;i++)
{
int now=num[i].ri-num[i].le+1;
if(now>=x)
continue;
if(need[x-now])
minn=min(minn,need[x-now]+num[i].cost);
if(i!=n-1)
while(again[index].ri<num[i+1].le)
{
now=again[index].ri-again[index].le+1;
if(need[now])
need[now]=min(need[now],again[index].cost);
else
need[now]=again[index].cost;
index++;
}
}
if(minn==2e9+1)
cout<<-1<<endl;
else
cout<<minn<<endl;
return 0;
}
右端点vector记录写法:202ms(本以为这个是最优的。。。)
#include<bits/stdc++.h>
using namespace std;
struct node
{
int le,ri,cost;
}num[200005];
int need[200005];
int cmp(node u,node v)
{
if(u.le==v.le)
return u.ri<v.ri;
return u.le<v.le;
}
vector<node>again[200005];
int main()
{
int i,n,x,l,r,c,ban;
cin>>n>>x;
for(i=0;i<n;i++)
scanf("%d %d %d",&num[i].le,&num[i].ri,&num[i].cost),again[num[i].ri].push_back(num[i]);
sort(num,num+n,cmp);
int minn=2e9+1,index=0;
for(i=0;i<n;i++)
{
int now=num[i].ri-num[i].le+1;
if(now>=x)
continue;
if(need[x-now])
minn=min(minn,need[x-now]+num[i].cost);
if(i!=n-1)
for(;index<num[i+1].le;index++)
{
for(int j=0;j<again[index].size();j++)
{
now=again[index][j].ri-again[index][j].le+1;
if(need[now])
need[now]=min(need[now],again[index][j].cost);
else
need[now]=again[index][j].cost;
}
}
}
if(minn==2e9+1)
cout<<-1<<endl;
else
cout<<minn<<endl;
return 0;
}
思路2:二分。和上面思路整体相同,vector【i】记录长度为i的所有区间,遍历每个区间,在长度匹配的区间里二分找合适的,事先求一个权值最小后缀,优化一下即可。
记得上次去西安遇到一个和这个类似的题目,卡了很长时间都没出。现在又是想了半天也没有思路。。。。
相关文章推荐
- Codeforces 822C Hacker, pack your bags!【排序+二分】
- Codeforces Round #422 (Div. 2) C. Hacker, pack your bags! 排序,贪心
- Codeforces Round #422 (Div. 2) C. Hacker, pack your bags! 排序, 贪心, 暴力(居然可以n方暴力)
- 【Codeforces Round #422 (Div. 2) C】Hacker, pack your bags!(二分写法)
- Codeforces Round #422 (Div. 2) C Hacker, pack your bags! (二分orDP)
- CF422 div2 C. Hacker, pack your bags!
- Codeforces Round #422 C. Hacker, pack your bags! (二分)
- CF822C:Hacker, pack your bags!(思维)
- Codeforces Round #422 (Div. 2) C. Hacker, pack your bags!
- Codeforces 822C Hacker, pack your bags!(思维+技巧)
- Codeforces Round #422 (Div. 2) C. Hacker, pack your bags!
- Codeforces 822 C. Hacker, pack your bags! 思维
- CodeForces - 822C Hacker, pack your bags!(区间端点处理技巧+思维)
- Codeforces 822C: Hacker, pack your bags!【二分查找】【后缀最小值】
- Codeforces 822C - Hacker, pack your bags!(二分)
- Codeforces Round #422 (Div. 2) C. Hacker, pack your bags!
- 【Codeforces Round #422 (Div. 2) C】Hacker, pack your bags!(hash写法)
- A - Hacker, pack your bags! CodeForces - 822C(思路,排序)
- codeforces 822 C. Hacker, pack your bags!(思维+dp)
- CF822C Hacker, pack your bags! 【思维好题】