问题描述
有多个区间 \([l,r]\) ,在每个区间选一个点使得各点之和为 \(X\)
思路
每个区间选一个点组成的 \(x\) 的范围为 \([\) \(\sum_{i=1}^{n}{l_i}\) , \(\sum_{i=1}^{n}{r_i}\) \(]\),若所求 \(X\) 在此区间则可达
而后从后往前反推求出一组解
步骤
\(l_i\) \(r_i\) \(X=10\)
1 3
1 5
2 3
1. 令 \(L_i=\) \(\sum_{j=1}^{i}{l_j}\) , \(R_i=\) \(\sum_{j=1}^{i}{r_j}\) ,即对前 \(i\) 区间可达点集
\(L_i\) \(R_i\)
0 0
1 3
2 8
4 11
2. 令 \(ans[n]=X\),意味着前 \(n\) 个点和为 X ,而区间 \(n\) 可选范围为 \([2,3]\) ,因此要求前 \(n-1\) 需要可达范围为 \([X-3=7,X-2=8]\) 。而前 \(n-1\) 的可达范围是 \([2,8]\) ,存在交集(可证必有交集),在交集中任选一点(选四个边界即可)作为前 \(n-1\) 取下来的和,即新的 \(X\)
3. 而后不断重复 \(2\) 操作直至 \(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;
}
浙公网安备 33010602011771号