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);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM