Educational Codeforces Round 112 (Rated for Div. 2) 题解

比赛地址:https://codeforces.com/contest/1555

只有 ABCDE 的题解,F 不会。

A

设用了 \(x\) 个小份,\(y\) 个中份,\(z\) 个大份,那么我们要使得 \(6x+8y+10z\ge n\),并让 \(15x+20y+25z\) 最小。

这里有一个很好的性质:\(15x+20y+25z=\frac 52(6x+8y+10z)\)。所以只需最小化 \(6x+8y+10z\)

\(6x+8y+10z\) 可以取遍 \(\ge 6\) 的所有偶数,然后就做完了。

typedef long long ll;

void mian(){
	ll n;scanf("%lld",&n);
	if(n<=6)n=6;
	else if(n&1)n++;
	printf("%lld\n",n/2*5);
}

B

显然最好的办法是竖着或者横着移。分 \(4\) 类(往左移,往右移,往上移,往下移)讨论即可。

typedef long long ll;

inline int dis(int a,int b){
	return std::max(b-a,0);
}

void mian(){
	int w,h,x1,y1,x2,y2,w2,h2;
	scanf("%d%d%d%d%d%d%d%d",&w,&h,&x1,&y1,&x2,&y2,&w2,&h2);
	int w1=x2-x1,h1=y2-y1;
	if(w1+w2>w&&h1+h2>h)puts("-1");
	else{
		int ans=0x3f3f3f3f;
		bool okw=(w1+w2<=w),okh=(h1+h2<=h);
		if(okw)ans=std::min(ans,std::min(dis(x1,w2),dis(w-w2,x2)));
		if(okh)ans=std::min(ans,std::min(dis(y1,h2),dis(h-h2,y2)));
		printf("%d\n",ans);
	}
}

C

Alice 的走法只有 \(n\) 种情况,于是考虑枚举这 \(n\) 种情况。

Alice 走完后,剩下的有硬币的格子是第一行的一个后缀和第二行的一个前缀。Bob 要么就都取第一行的这个后缀,要么就都取第二行的这个前缀。

typedef long long ll;

const int N=1e5;

int n,a[2][N+10],sum1[2][N+10],sum2[2][N+10];

void mian(){
	for(int i=1;i<=n;i++)a[0][i]=sum1[0][i]=a[1][i]=sum1[1][i]=sum2[0][i]=sum2[1][i]=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[0][i]);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[1][i]);
	for(int i=1;i<=n;i++){
		sum1[0][i]=sum1[0][i-1]+a[0][i];
		sum1[1][i]=sum1[1][i-1]+a[1][i];
	}
	for(int i=n;i>=1;i--){
		sum2[0][i]=sum2[0][i+1]+a[0][i];
		sum2[1][i]=sum2[1][i+1]+a[1][i];
	}
	int ans=0x3f3f3f3f;
	for(int i=1;i<=n;i++)
		ans=std::min(ans,std::max(sum1[1][i-1],sum2[0][i+1]));
	printf("%d\n",ans);
}

D

美丽的字符串只可能是 \(\texttt{abcabcabc}\cdots\) 的子串或者是 \(\texttt{acbacbacb}\cdots\) 的子串。

每次询问我们把 \(\texttt{abc}\cdots,\texttt{bca}\cdots,\texttt{cab}\cdots,\texttt{acb}\cdots,\texttt{cba}\cdots,\texttt{bac}\cdots\)\(6\) 个串和要询问的串对比一下即可。

可以用前缀和维护一下。(我写了个线段树。。)

typedef long long ll;

const int N=2e5;

/*
 * 0 abc
 * 1 bca
 * 2 cab
 *
 * 3 acb
 * 4 cba
 * 5 bac
 */

struct Node{
	int val[6],len;
};

Node t[N*4+10];
int n,m;
char s[N+10];

inline int get(int x,int len){
	if(0<=x&&x<=2)return (x+len)%3;
	x-=3;
	return (x+len)%3+3;
}

#define ls(x) (x<<1)
#define rs(x) (x<<1|1)

inline Node pushUp(Node L,Node R){
	Node res;
	for(int i=0;i<6;i++)res.val[i]=L.val[i]+R.val[get(i,L.len)];
	res.len=L.len+R.len;
	return res;
}

void build(int i,int l,int r){
	if(l==r){
		if(s[l]=='a')t[i].val[1]=t[i].val[2]=t[i].val[4]=t[i].val[5]=1;
		if(s[l]=='b')t[i].val[0]=t[i].val[2]=t[i].val[3]=t[i].val[4]=1;
		if(s[l]=='c')t[i].val[0]=t[i].val[1]=t[i].val[3]=t[i].val[5]=1;
		t[i].len=1;
		return;
	}
	int mid=(l+r)>>1;
	build(ls(i),l,mid);
	build(rs(i),mid+1,r);
	t[i]=pushUp(t[ls(i)],t[rs(i)]);
}

Node query(int i,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr)return t[i];
	int mid=(l+r)>>1;
	if(ql>mid) return query(rs(i),mid+1,r,ql,qr);
	if(qr<=mid)return query(ls(i),l,mid,ql,qr);
	return pushUp(query(ls(i),l,mid,ql,qr),query(rs(i),mid+1,r,ql,qr));
}

#undef ls
#undef rs

void mian(){
	scanf("%d%d",&n,&m);
	scanf("%s",s+1);
	build(1,1,n);
	while(m--){
		int l,r;scanf("%d%d",&l,&r);
		Node res=query(1,1,n,l,r);
		int ans=0x3f3f3f3f;
		for(int i=0;i<6;i++)
			ans=std::min(ans,res.val[i]);
		printf("%d\n",ans);
	}
}

E

先按 \(w\) 将线段排序。

双指针。边扫边维护 \([1,m-1]\)(为什么要 \(-1\) 一会再解释)中每个点被线段覆盖了多少次,如果覆盖次数的全局 \(\min\) 等于 \(0\),说明有一些点没被覆盖到,还要再往右扫。否则就统计答案。

小细节:所有线段的右端点要 \(-1\)。比如说有两个线段 \([1,3]\)\([4,7]\),他们是没法覆盖 \([1,7]\) 的。

typedef long long ll;

const int N=3e5;
const int M=1e6;

struct Node{
	int mn,atag;
};

struct Node2{
	int l,r,w;
	inline bool operator<(const Node2 &rhs)const{
		return w<rhs.w;
	}
};

Node t[M*4+10];
int n,m;
Node2 a[N+10];

#define ls(x) (x<<1)
#define rs(x) (x<<1|1)

inline void pushUp(int i){
	t[i].mn=std::min(t[ls(i)].mn,t[rs(i)].mn);
}

inline void pushA(int i,int atag){
	t[i].atag+=atag;
	t[i].mn+=atag;
}

inline void pushDown(int i){
	if(t[i].atag){
		pushA(ls(i),t[i].atag);
		pushA(rs(i),t[i].atag);
		t[i].atag=0;
	}
}

void modify(int i,int l,int r,int ql,int qr,int x){
	if(ql<=l&&r<=qr)return pushA(i,x),void();
	int mid=(l+r)>>1;
	pushDown(i);
	if(ql<=mid)modify(ls(i),l,mid,ql,qr,x);
	if(qr>mid) modify(rs(i),mid+1,r,ql,qr,x);
	pushUp(i);
}

#undef ls
#undef rs

void mian(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w);
	std::sort(a+1,a+n+1);
	int l=1,r=1,ans=0x3f3f3f3f;
	while(l<=n){
		while(r<=n&&t[1].mn==0)modify(1,1,m-1,a[r].l,a[r].r-1,1),r++;
		if(t[1].mn>0)ans=std::min(ans,a[r-1].w-a[l].w);
		modify(1,1,m-1,a[l].l,a[l].r-1,-1);
		l++;
	}
	printf("%d\n",ans);
}
posted @ 2021-07-31 09:58  registerGen  阅读(282)  评论(1编辑  收藏  举报