题意:
给出 l 1 , r 1 , l 2 , r 2 , n , k l1,r1,l2,r2,n,k l1,r1,l2,r2,n,k
初始a集合表示n个区间 [ l 1 , r 1 ] [l1,r1] [l1,r1]
b集合表示n个区间 [ l 2 , r 2 ] [l2,r2] [l2,r2]
你一次操作能把一个区间 [ x , y ] [x,y] [x,y]扩大成 [ x − 1 , y ] [x-1,y] [x−1,y]或 [ x , y + 1 ] [x,y+1] [x,y+1]
问至少多少次操作,使得 ∑ i = 1 i = n b i & a i \sum_{i=1}^{i=n}b_i\&a_i ∑i=1i=nbi&ai
其中 a i & b i a_i\&b_i ai&bi在这里指两个区间的相交线段长度
Ⅰ . 分 析 问 题 \color{Red}Ⅰ.分析问题 Ⅰ.分析问题
很明显可以分成 [ l 1 , r 1 ] [l1,r1] [l1,r1]和 [ l 2 , r 2 ] [l2,r2] [l2,r2]是否相交的情况
Ⅰ . 相 交 时 \color{Red}Ⅰ.相交时 Ⅰ.相交时
初 始 每 个 区 间 有 l e n = m i n ( r 1 , r 2 ) − m a x ( l 1 , l 2 ) 的 线 段 长 度 相 交 初始每个区间有len=min(r1,r2)-max(l1,l2)的线段长度相交 初始每个区间有len=min(r1,r2)−max(l1,l2)的线段长度相交
所 以 初 始 状 态 有 s l e n = l e n ∗ n 长 度 所以初始状态有slen=len*n长度 所以初始状态有slen=len∗n长度
拿 k − = s l e n , 若 k 为 负 数 则 一 次 都 不 用 操 作 拿k-=slen,若k为负数则一次都不用操作 拿k−=slen,若k为负数则一次都不用操作
否 则 继 续 看 否则继续看 否则继续看
我 们 可 以 只 扩 大 a 集 合 区 间 的 右 端 点 就 能 填 充 w 我们可以只扩大a集合区间的右端点就能填充w 我们可以只扩大a集合区间的右端点就能填充w
我 们 可 以 只 扩 大 b 集 合 区 间 的 左 端 点 就 能 填 充 q 我们可以只扩大b集合区间的左端点就能填充q 我们可以只扩大b集合区间的左端点就能填充q
这 样 的 操 作 一 直 持 续 q + w 次 可 以 一 次 操 作 增 加 1 长 度 这样的操作一直持续q+w次可以一次操作增加1长度 这样的操作一直持续q+w次可以一次操作增加1长度
也 就 最 多 有 n ∗ ( q + w ) 次 1 换 1 的 机 会 也就最多有n*(q+w)次1换1的机会 也就最多有n∗(q+w)次1换1的机会
用 完 之 后 , a 区 间 和 b 区 间 重 合 , 就 只 有 2 换 1 的 机 会 ( a 区 间 往 左 扩 大 , b 区 间 也 往 左 扩 大 ) 用完之后,a区间和b区间重合,就只有2换1的机会(a区间往左扩大,b区间也往左扩大) 用完之后,a区间和b区间重合,就只有2换1的机会(a区间往左扩大,b区间也往左扩大)
简 单 计 算 一 下 即 可 简单计算一下即可 简单计算一下即可
Ⅱ . 不 相 交 时 \color{Red}Ⅱ.不相交时 Ⅱ.不相交时
首 先 要 使 区 间 相 交 , 代 价 是 c o = m i n ( r 1 − l 2 , r 2 − l 1 ) 首先要使区间相交,代价是co=min(r1-l2,r2-l1) 首先要使区间相交,代价是co=min(r1−l2,r2−l1)
假 设 现 在 必 须 使 x 个 区 间 相 交 最 划 算 , 那 么 有 x ∗ c o 的 操 作 用 来 相 交 假设现在必须使x个区间相交最划算,那么有x*co的操作用来相交 假设现在必须使x个区间相交最划算,那么有x∗co的操作用来相交
然 后 你 有 [ m a x ( r 1 , r 2 ) − m i n ( l 1 , l 2 ) ] ∗ n 的 机 会 1 换 1 ( 1 次 操 作 增 加 1 ) 然后你有[max(r1,r2)-min(l1,l2)]*n的机会1换1(1次操作增加1) 然后你有[max(r1,r2)−min(l1,l2)]∗n的机会1换1(1次操作增加1)
然 后 你 有 无 限 次 机 会 2 换 1 然后你有无限次机会2换1 然后你有无限次机会2换1
至于x怎么最优,for大力枚举即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,l1,r1,l2,r2,t,k;
int main()
{
cin >> t;
while( t-- )
{
ll ans=1e18;
cin >> n >> k;
cin >> l1 >> r1 >> l2 >> r2;
if( r1<l2||l1>r2 )//一开始不相交的情况
{
ll temp=0,len=max(r1,r2)-min(l1,l2);
if( r1<=l2) temp=l2-r1;
else if( l1>=r2 ) temp=l1-r2;//temp表示需要操作temp次使线段相交
for(ll i=1;i<=n;i++)//枚举使几个线段相交
{
ll sumn=len*i;//有sumn次1换1的机会
if( sumn>=k ) ans=min(ans,temp*i+k);
else ans=min(ans,len*i+temp*i+(k-sumn)*2);
}
cout << ans << endl;
}
else
{
ll jiao=min(r1,r2)-max(l1,l2);//初始相交长度
ll len=max(r1,r2)-min(l1,l2)-jiao;//有len次1换1的机会
k-=jiao*n;
if( k<=0 ) cout << 0 << endl;
else if( len*n>=k ) cout << k << "\n";
else
cout << len*n+(k-len*n)*2 << "\n";
}
}
}