题解 AT2536 切符の手配 (Arranging Tickets)
JOISC 2017 Day2 T1,神题。
我们转化一下题意,转化为有若干个区间
- 性质 1:反转的区间的交集一定不为空。
因为如果为空,那么一定能找到两个反转的区间使得它们不交。如果两个区间不交,那么将其反转肯定不优,因为会覆盖原来有的位置。
也就是说,我们一定能找到一个位置
先二分答案
也就是说我们先枚举
时间复杂度
接下来的部分就越来越牛了。
- 性质 2:我们一定能找到一个
x 满足b_x=\max(b_i) 或\max(b_i)-1 。
证明考虑如果当前
也就是说我们不用枚举
时间复杂度变成了
- 性质 3 最优方案中的:
[L,R] 中一定能找到一个位置x 使得a_x=\max(a_i) 。
考虑性质 2 反证,假设
- 性质 4:最优方案中的
x 取任意一个a_x=\max(a_i) 均可。
证明方法和性质 3 的方法差不多,考虑性质 2 反证即可,留给读者思考。
代码难度很小,但是这个思考真的很神,从一个看上去复杂度上天的做法通过不断证明合法的位置只有
#include<bits/stdc++.h>
#define poly vector<int>
#define IOS ios::sync_with_stdio(false)
#define ll long long
#define mp make_pair
#define mt make_tuple
#define pa pair < int,int >
#define fi first
#define se second
#define inf 1e18
#define mod 998244353
#define int ll
#define N 300005
using namespace std;
inline char gc(){static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
#define gc getchar
inline ll read(){char c=gc();ll su=0,f=1;for (;c<'0'||c>'9';c=gc()) if (c=='-') f=-1;for (;c>='0'&&c<='9';c=gc()) su=su*10+c-'0';return su*f;}
inline void write(ll x){if (x<0){putchar('-');write(-x);return;}if (x>=10) write(x/10);putchar(x%10+'0');}
inline void writesp(ll x){write(x),putchar(' ');}
inline void writeln(ll x){write(x);putchar('\n');}
int f[N],b[N],Pre[N],l[N],r[N],w[N];
vector<pa>G[N];
int a[N];
int n,m;
int nowx;
int ans,ans1;
bool chk(int x,int y)
{
for (int i=1;i<=n;i++)
Pre[i]=0,f[i]=0,b[i]=0;
Pre[nowx]=a[nowx]-x+y;
for (int i=1;i<=nowx;i++)
Pre[i]=max(0ll,(int)((a[i]+Pre[nowx]-x+1)/2));
priority_queue<pair<pa,int>>q;
int nowy=0;
for (int i=1;i<=nowx;i++)
{
for (auto U:G[i])
{
int u=U.fi,w=U.se;
if (u>=nowx)
{
q.push(mp(mp(u,i),w));
}
}
while (!q.empty()&&f[i]+nowy<Pre[i])
{
int x=q.top().fi.se,y=q.top().fi.fi,w=q.top().se;
q.pop();
if (f[i]+w+nowy>Pre[i])
{
int z=min(Pre[i]-f[i]-nowy,w);
nowy+=z;
b[x]-=z,b[y+1]+=z;
b[1]+=z,b[x]-=z,b[y+1]+=z;
q.push(mp(mp(y,x),w-z));
break;
}
int z=w;
nowy+=z;
b[x]-=z,b[y+1]+=z;
b[1]+=z,b[x]-=z,b[y+1]+=z;
}
if (f[i]+nowy<Pre[i]) return 0;
}
for (int i=1;i<=n;i++) b[i]+=b[i-1];
for (int i=1;i<=n;i++)
if (b[i]+a[i]>x) return 0;
return 1;
}
void BellaKira()
{
n=read(),m=read();
int t=0;
int sg=0;
for (int i=1;i<=m;i++)
{
l[i]=read(),r[i]=read(),w[i]=read();
sg+=w[i];
if (l[i]>r[i]) swap(l[i],r[i]);
r[i]--;
}
for (int i=1;i<=m;i++) a[l[i]]+=w[i],a[r[i]+1]-=w[i],G[l[i]].push_back(mp(r[i],w[i]));
nowx=0;
for (int i=1;i<=n;i++)
{
a[i]+=a[i-1];
if (a[i]>a[nowx]) nowx=i;
}
int l=0,r=sg;
while (l<=r)
{
int mid=l+(r-l)/2;
if (chk(mid,0)||chk(mid,1))
{
ans1=mid;
r=mid-1;
} else l=mid+1;
}
writeln(ans1);
}
signed main()
{
int T=1;
while (T--)
{
BellaKira();
}
}
/*
*/