The 2018 ACM-ICPC Asia Qingdao Regional Contest (E,I,K)
10.3 The 2018 ACM-ICPC Asia Qingdao Regional Contest
只有自己写的/改的题。
E.Plants vs. Zombies(二分)√
二分答案。最优解就是从左往右,每次走完一个格子需要的步数再向右。
要注意每次要走一步到下一个格子,但如果走\(n-1\)时满足了\(n\)的需求就不用再走一步到\(n\)。
因为写法问题WA了n次。。
//502ms 868kB
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=2e5+5;
int A[N];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
bool Check(int n,LL m,LL pur)
{
LL need=0;
for(int i=1; i<=n; ++i)
{
LL need2=(pur+A[i]-1)/A[i];
need2-=need+1;
if(need2<=0) i!=n?(--m):(!need2/*还需一步到n*/&&--m), need2=0;
else m-=need2*2+1;
if(m<0) return 0;
need=need2;
}
return 1;
}
int main()
{
for(int T=read(); T--; )
{
int n=read(); LL m; scanf("%lld",&m);
for(int i=1; i<=n; ++i) A[i]=read();
LL l=0,r=1e17,mid,ans=0;
while(l<=r)
if(Check(n,m,mid=l+r>>1)) ans=mid, l=mid+1;
else r=mid-1;
printf("%lld\n",ans);
}
return 0;
}
I.Soldier Game(枚举 线段树)
\(Description\)
有\(n\)个物品,每个价值为\(a_i\)。现在要将每个物品或相邻的两个物品划分为一组,一组的权值为组中物品价值之和(每个物品属于且只属于一组)。
求划分后组的最大权值-最小权值的最小值。
\(n\leq 10^5,\ \sum n\leq 10^6\)。
\(Solution\)
最大值-最小值,考虑枚举!
区间只有\(2n\)个,可以将\(2n\)个区间排序,从小到大枚举最小值。
记\(\min\{\max\}\)表示令最大值最小时的最大值。枚举最小值区间\(i\)后,要用剩下的区间覆盖\(1\sim n\)且使最大值最小,并求一个\(\min{\max}\),然后把区间\(i\)删掉(不能再作为最大值区间)。
最简单的是一个\(O(n)\)DP。可以发现这是一个每次删除一个区间,且答案与递推顺序无关(可以合并区间)的DP,可以用线段树维护。
线段树每个区间维护四个值:
\(lmx\):包含左端点但不包含右端点的区间\(\min\{\max\}\)。
\(rmx\):包含右端点但不包含左端点的区间\(\min\{\max\}\)。
\(mx\):左右端点都不包含的区间\(\min\{\max\}\)。
\(ans\):包含左右端点(即整个区间)的\(\min\{\max\}\)。
就可以合并区间了(初始化即长度为\(1\)的区间,合并区间时要用到长度为\(2\)的区间)。
删除区间的时候可以直接将区间赋值为\(INF\)(一定不会取)。
还有一个点是,最优解中最大值和最小值区间一定不会重叠(除了n=1或2),所以可以直接查询更新再删除(大概是这样)。
PS: 单点初始化时用长度为1,2的区间举个例子,lmx,rmx不存在就是-INF(取max不影响答案的取值),mx不合法就是INF(长度为1的区间不能用mx更新)。
最小的区间是-2e9,最大的区间可能为1e9,即求答案过程中可能爆int(虽然最终答案int内)。
//299ms 6768kB
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define mp std::make_pair
#define pr std::pair<int,int>
typedef long long LL;
const int N=1e5+5,INF=2e9+10;
int A[N],B[N];
pr Ref[N<<1];
struct Segment_Tree
{
#define S N<<2
int lmx[S],rmx[S],mx[S],ans[S];
#undef S
#define ls rt<<1
#define rs rt<<1|1
#define lson l,m,ls
#define rson m+1,r,rs
inline void Update(int rt,int mid)//B:长度为2的区间 B[mid]就是合并时区间相交段的值!
{
int l=ls,r=rs;
lmx[rt]=std::min(std::max(lmx[rs],ans[ls]),std::max(mx[rs],std::max(B[mid],lmx[ls])));
rmx[rt]=std::min(std::max(rmx[ls],ans[rs]),std::max(mx[ls],std::max(B[mid],rmx[rs])));
mx[rt]=std::min(std::max(rmx[ls],lmx[rs]),std::max(mx[ls],std::max(B[mid],mx[rs])));
ans[rt]=std::min(std::max(ans[ls],ans[rs]),std::max(lmx[ls],std::max(B[mid],rmx[rs])));
}
void Build(int l,int r,int rt)
{
if(l==r)
{
lmx[rt]=-INF, rmx[rt]=-INF, mx[rt]=INF/*!*/, ans[rt]=A[l];
return;
}
int m=l+r>>1;
Build(lson), Build(rson), Update(rt,m);
}
void Modify(int l,int r,int rt,int p)
{
if(l==r)
{
ans[rt]=A[l];
return;
}
int m=l+r>>1;
p<=m ? Modify(lson,p) : Modify(rson,p);
Update(rt,m);
}
}T;
inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now*f;
}
int main()
{
for(int Ts=read(); Ts--; )
{
int n=read(),cnt=n+n-1;
for(int i=1; i<=n; ++i) Ref[i]=mp(A[i]=read(),i);
for(int i=1; i<n; ++i) Ref[i+n]=mp(B[i]=A[i]+A[i+1],i+n);
std::sort(Ref+1,Ref+1+cnt);
LL ans=1e14;
T.Build(1,n,1);
for(int i=1; i<=cnt && T.ans[1]!=INF; ++i)
{
ans=std::min(ans,1ll*T.ans[1]-Ref[i].first);
int t=Ref[i].second;
t<=n ? (A[t]=INF,T.Modify(1,n,1,t)) : (B[t-n]=INF,T.Modify(1,n,1,t-n));
}
printf("%lld\n",ans);
}
return 0;
}
/*
1 4
1000000000 1000000000 -1000000000 -1000000000
*/
K.Airdrop(思路 枚举)
\(Description\)
二维平面上有\(n\)个玩家,每个玩家在\((x_i,y_i)\)处。有一个补给箱掉落在\((X,Y)\)处,其中\(Y\)已知\(X\)不确定。
每个玩家在一个单位时间内会向补给箱移动一个单位,移动规则:向上下移动到和\(Y\)同一横坐标后再左右,直到到补给箱处。若两个或多个玩家同时在非补给箱位置的某处相遇则会全部出局。
求\(X\)不确定情况下出局的最多人数和最少人数。
\(Solution\)
这题过的人少但不难。。
易知两个或多个人相遇的条件是,他们到\((X,Y)\)的曼哈顿距离相同,即\(|x_i-X|+|y_i-Y|\)相同。
考虑枚举\(X\)(最多考虑\(2n\)个),对于\((X,Y)\)左边的人,若相遇,则有\(|X-x_i|+|y_i-Y|\)相同,也就是\(|y_i-Y|-x_i\)相同。从左到有枚举\(X\)并记录某个值是否出现即可。
对于\(X\)右边的就是\(|y_i-Y|+x_i\)相同。
然后是某些细节:三个曼哈顿距离相同的点\(i,j,k\),前两个可能会早就相遇然后out,第三个不会出局。可以发现要么是前两个\(x\)相同,要么是\(x_i<x_j<x_k\),\(k\)不出局。对于前一种情况记录每个值的\(las\),后一种情况记一个\(tag\)即可。
注意下多个人同时出局的情况。
此外我这个写法要注意,\(x\)相同的点只能在\(X\)枚举到\(x\)时更新一次答案(否则不对)。
写的有些乱,不多说了。。自己模拟下就ok。
//309ms 4172kB
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=1e5+5,M=3e5+15,lim=1e5+2;
int tag[M],tmp[M],las[M];
struct Node
{
int val,x;
bool operator <(const Node &a)const
{
return x==a.x?val<a.val:x<a.x;
}
}A[M];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
int main()
{
for(int Ts=read(); Ts--; )
{
int n=read(),y=read();
for(int i=1,X,Y; i<=n; ++i) X=read(), Y=read(), A[i]=(Node){std::abs(Y-y)-X+lim,X};//[-1e5,1e5)->(0,2e5]
std::sort(A+1,A+1+n);
int cnt=n;
for(int i=1; i<n; ++i) if(A[i].x+1<A[i+1].x) A[++cnt]=(Node){0,A[i].x+1};
A[++cnt]=(Node){0,0}, A[++cnt]=(Node){0,A[n].x+1}, std::sort(A+1,A+1+cnt);
A[0].x=A[1].x-1, A[cnt+1].x=A[cnt].x+1;
for(int i=1,ans=0,t,x,j,a; i<=cnt; i=j)
{
for(j=i,a=ans; A[j].x==A[i].x; ++j)
{
tmp[j]=a;
if(t=A[j].val)
{
x=A[j].x;
if(las[t])
if(las[t]==x) tag[t]?++ans:ans+=2, las[t]=0, tag[t]=0;
else if(!tag[t]) ans+=2, las[t]=x, tag[t]=1;
else las[t]=x, tag[t]=0;
else las[t]=x;
}
}
}
for(int i=1,t; i<=cnt; ++i) tag[t=A[i].val]=0, las[t]=0, t&&(A[i].val+=2*A[i].x);//(0,2e5)->(1e5,3e5)
int mn=N,mx=0;
for(int i=cnt,ans=0,t,x,j; i; i=j)
{
mn=std::min(mn,ans+tmp[i]), mx=std::max(mx,ans+tmp[i]);
for(j=i; A[j].x==A[i].x; --j)
{
if(t=A[j].val)
{
x=A[j].x;
if(las[t])
if(las[t]==x) tag[t]?++ans:ans+=2, las[t]=0, tag[t]=0;
else if(!tag[t]) ans+=2, las[t]=x, tag[t]=1;
else las[t]=x, tag[t]=0;
else las[t]=x;
}
}
}
for(int i=1; i<=cnt; ++i) tag[A[i].val]=0, las[A[i].val]=0;
printf("%d %d\n",n-mx,n-mn);
}
return 0;
}
很久以前的奇怪但现在依旧成立的签名
attack is our red sun $$\color{red}{\boxed{\color{red}{attack\ is\ our\ red\ sun}}}$$ ------------------------------------------------------------------------------------------------------------------------