D - Segment Intersections (Round 92 div2 模拟 枚举)

D - Segment Intersections *

题意: 分别给出 n 个区间 [ a l 1 , a r 1 ] , [ a l 2 , a r 2 ] , … , [ a l n , a r n ] [al_1, ar_1], [al_2, ar_2], \dots, [al_n, ar_n] [al1,ar1],[al2,ar2],,[aln,arn] 其初始值均为 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] [ b l 1 , b r 1 ] , [ b l 2 , b r 2 ] , … , [ b l n , b r n ] [bl_1, br_1], [bl_2, br_2], \dots, [bl_n, br_n] [bl1,br1],[bl2,br2],,[bln,brn] 其初始值均为 [ l 2 , r 2 ] [l_2,r_2] [l2,r2]。定义: ( [ a l i , a r i ] , [ b l i , b r i ] ) ([al_i, ar_i], [bl_i, br_i]) ([ali,ari],[bli,bri]) 为两个区间的交集长度,求这 n 对区间的交集长度之和大于等于 k 所需要的最少操作次数。 每次操作可以延长区间一个单位。
思路: 其实就是分类讨论两个区间的关系:
1、两区间相交,设相交长度为 len ,则初始值为 len * n ,之后往左边或右边没有相交的区间延长端点时均为1换1的代价,之后再延长既是2换1的代价。
2、同理,先把区间延长至相交,然后与之不同的是我们也要枚举延长的区间个数,同时计算代价,然后取最小的代价即可。(因为每多延长一对区间至相交时所花费代价不知是否值得)

Code:

#include
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long LL;

int main()
{
	IO;
	int T; cin>>T;
	while(T--){
		LL n,k,l1,r1,l2,r2;
		cin>>n>>k>>l1>>r1>>l2>>r2;
		if(r1<l2||r2<l1){  //不相交 
			LL s = min(abs(l2-r1),abs(l1-r2));  //间隔长度
			LL len = max(r1,r2)-min(l1,l2);   //连接两个区间后的总长度
			LL ans = 1e18;
			for(int i=1;i<=n;i++){  //枚举需要相交的区间数,取最值
				if(len*i>=k) ans = min(ans,s*i+k);
				else ans = min(ans,s*i+len*i+(k-len*i)*2);
			}
			cout<<ans<<"\n";
		}else{   //相交
			LL t = min(r1,r2)-max(l1,l2);  //相交长度
			k-=t*n;
			if(k<=0) cout<<"0\n";
			else {
				t = abs(r1-r2)+abs(l1-l2); //1换1 的长度
				if(k<=t*n) cout<<k<<"\n";
				else cout<<t*n+(k-t*n)*2<<"\n";  //剩下的2换1
			}
		}
	}
	return 0;
}

你可能感兴趣的:(CF)