问题描述
有多个区间 [ l , r ] [l,r] [l,r] ,在每个区间选一个点使得各点之和为 X X X
思路
每个区间选一个点组成的
x
x
x 的范围为
[
[
[
∑
i
=
1
n
l
i
\sum_{i=1}^{n}{l_i}
∑i=1nli ,
∑
i
=
1
n
r
i
\sum_{i=1}^{n}{r_i}
∑i=1nri
]
]
],若所求
X
X
X 在此区间则可达
而后从后往前反推求出一组解
步骤
l i l_i li r i r_i ri X = 10 X=10 X=10
1 3
1 5
2 3
1. 令 L i = L_i= Li= ∑ j = 1 i l j \sum_{j=1}^{i}{l_j} ∑j=1ilj , R i = R_i= Ri= ∑ j = 1 i r j \sum_{j=1}^{i}{r_j} ∑j=1irj ,即对前 i i i 区间可达点集
L i L_i Li R i R_i Ri
0 0
1 3
2 8
4 11
2. 令
a
n
s
[
n
]
=
X
ans[n]=X
ans[n]=X,意味着前
n
n
n 个点和为 X ,而区间
n
n
n 可选范围为
[
2
,
3
]
[2,3]
[2,3] ,因此要求前
n
−
1
n-1
n−1 需要可达范围为
[
X
−
3
=
7
,
X
−
2
=
8
]
[X-3=7,X-2=8]
[X−3=7,X−2=8] 。而前
n
−
1
n-1
n−1 的可达范围是
[
2
,
8
]
[2,8]
[2,8] ,存在交集(可证必有交集),在交集中任选一点(选四个边界即可)作为前
n
−
1
n-1
n−1 取下来的和,即新的
X
X
X
3. 而后不断重复
2
2
2 操作直至
i
=
1
i=1
i=1
代码
Codeforces Round #753 (Div. 3-G. Banquet Preparations 1)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2e5+9;
int T,n;
LL m,tot;
LL sx[N],sy[N],l[N],r[N],L[N],R[N],ans[N];
LL Intersect(LL ltot,LL rtot,LL ltl,LL ltr)
{
if(ltot>=ltl&<ot<=ltr) return ltot;
if(rtot>=ltl&&rtot<=ltr) return rtot;
if(ltl>=ltot&<l<=rtot) return ltl;
return ltr;
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>sx[i]>>sy[i];
LL x=sx[i],y=sy[i];
int miny=max(0ll,y-m);
int minx=x-(m-(y-miny));
l[i]=miny-minx;
int maxx=max(0ll,x-m);
int maxy=y-(m-(x-maxx));
r[i]=maxy-maxx;
}
for(int i=1;i<=n;i++)
{
L[i]=L[i-1]+l[i];
R[i]=R[i-1]+r[i];
}
if(0<L[n]) tot=L[n];
else if(0>R[n]) tot=R[n];
else
{
if(abs(L[n])%2==0) tot=0;
else tot=1;
}
cout<<abs(tot)<<endl;
for(int i=n;i>=1;i--)
{
LL ltot=tot-r[i],rtot=tot-l[i];
LL ntot=Intersect(ltot,rtot,L[i-1],R[i-1]);
ans[i]=tot-ntot;
tot=ntot;
}
for(int i=1;i<=n;i++)
{
LL x=(sx[i]+sy[i]-m-ans[i])/2;
cout<<sx[i]-x<<" "<<sy[i]-(x+ans[i])<<endl;
}
}
int main()
{
cin>>T;
while(T--) solve();
return 0;
}