CF-Educational 76 A,B,C,D,E

Contest:https://codeforces.com/contest/1257

目录

A-Two Rival Students(暴力)

B- Magic Stick(规律)

C-Dominated Subarray(暴力)

D-Yet Another Monster Killing Problem(思维+暴力)

E-The Contest(思维+DP)


A-Two Rival Students(暴力)

题目链接:https://codeforces.com/contest/1257/problem/A

题目大意:n个人,可以调换x次,两个对手分别在位置a和b处,问最远能够让对手距离多远,每次换位置只能和身边的人交换。

思路:最左边的向左移动,最右边的向右移动,直到没有机会为止。

ACCode:

int main(){
	int T;scanf("%d",&T);
	while(T--){
		int n,x,a,b;scanf("%d%d%d%d",&n,&x,&a,&b);
		if(a>b) swap(a,b);
		for(x;x>=1&&a>=2;--x) --a;
		for(x;x>=1&&b<=n-1;--x) ++b;
		printf("%d\n",b-a);
	}
	
}

B- Magic Stick(规律)

题目链接:https://codeforces.com/contest/1257/problem/B

题目大意:给出x和y。x有两种操作:1.当且仅当x%2==0时,x=x*3/2。2.x=x-1;可以进行无限次操作,问x是否能变成y。

思路:首先容易发现,x=2时只能变成3,2,1。x=3时只能变成3,2,1。x=4时就是无限了。特判一下就好了。

ACCode:

int main(){
	int T;scanf("%d",&T);
	while(T--){
		ll x,y;scanf("%lld%lld",&x,&y);
		if(x>=y){
			printf("YES\n");continue ;
		}
		if(x==1||x==3){
			printf("NO\n");continue ;
		}
		if(x==2&&y>3){
			printf("NO\n");continue ;
		}
		printf("YES\n"); 
	}
	
}

C-Dominated Subarray(暴力)

题目链接:https://codeforces.com/contest/1257/problem/C

题目大意:给出n个元素的数组A。A的支配元素就是A中数量最多的元素。一个数组的支配元素只能有1个。现在求数组A的连续子数组,问最短的有支配元素的子数组的长度。

思路:很容易发现,找到最近的两个相同的元素就好了。

ACCode:

int A[MAXN],Cnt[MAXN],Pre[MAXN];
int n;
 
int main(){
	int Cas;scanf("%d",&Cas);
	while(Cas--){
		scanf("%d",&n);
		for(int i=1;i<=n;++i) Cnt[i]=0;
		for(int i=1;i<=n;++i) scanf("%d",&A[i]);
		for(int i=1;i<=n;++i) Cnt[A[i]]++;
		int maxcnt=0;
		for(int i=1;i<=n;++i) maxcnt=max(maxcnt,Cnt[i]);//得到支配值的数量 
		if(maxcnt==1||n==1){
			printf("-1\n");continue ;
		}
		for(int i=1;i<=n;++i) Cnt[i]=0,Pre[i]=-1;
		int ans=n;
		for(int i=1;i<=n;++i){
			Cnt[A[i]]++;
			if(Cnt[A[i]]==1){
				Pre[A[i]]=i;
			}
			else{
				ans=min(ans,i-Pre[A[i]]+1);
				Pre[A[i]]=i;
			}
		}printf("%d\n",ans);
	}
	
}

D-Yet Another Monster Killing Problem(思维+暴力)

题目链接:https://codeforces.com/contest/1257/problem/D

题目大意:给出n个怪物的防御。m个英雄的攻击p和耐力s。如果英雄的攻击<怪物的防御,没有伤害,否则会直接秒杀怪物。英雄一次可以连续攻击s下。问最后按顺序消灭所有怪物,最少多少次英雄。同一个英雄可以使用多次。

思路:我们对耐力进行处理。Atk[i]表示耐力为i的情况最高攻击力是多少。这样就可以枚举怪物了。对于一次攻击。枚举耐力。找到最大的耐力满足Atk[i]>=Hp[j]。就可以直接求出了。

ACCode:

int Atk[MAXN];
int Hp[MAXN];
int n,m;
 
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;++i) Atk[i]=0;
		for(int i=1;i<=n;++i) scanf("%d",&Hp[i]);
		scanf("%d",&m);
		for(int i=1;i<=m;++i){
			int p,s;scanf("%d%d",&p,&s);
			if(Atk[s]<p) Atk[s]=p;//耐久为s的最高攻击力 
		}
		for(int i=n-1;i>=1;--i){
			Atk[i]=max(Atk[i],Atk[i+1]);
		}
		int flag=1,ans=0;
		for(int pos=1,j;pos<=n;pos=j){
			int maxhp=Hp[pos];
			if(maxhp>Atk[1]){//该点总是过不去 
				flag=0;break;
			}
			for(j=pos;j<=n;++j){//最远能走多远 
				maxhp=max(maxhp,Hp[j]);//最大血量 
				if(Atk[j-pos+1]>=maxhp) continue ;//可以打这么多下 
				//打不了这么多下 
				break;
			}ans++;
		}
		if(flag) printf("%d\n",ans);
		else printf("-1\n");
	}
	
}

E-The Contest(思维+DP)

题目链接:https://codeforces.com/contest/1257/problem/E

题目大意:给出三个人,一开始每个人有手头都有ki个任务,然后给出每个人的手头任务。但是,第一个人只完成连续的前n个。第二个人只完成连续的中间的。第三个人只完成连续的最后面的。问这些人需要将任务最少交换多少次才能满足每个人的需求。

思路:注意有些人可以不完成任务,有些人可以完成所有的任务。先将每个人的任务排一下序

枚举第一个人完成的任务个数,[0,i]。记录一下要完成i个任务,需要丢弃多少任务Cnt1[i].

枚举第三个人完成的任务个数,[i,n+1]。记录一下要完成i个任务,需要丢弃的任务数量Cnt[i];

对于第二个人。我们容易发现:

当他要完成[l,n]个任务的时候。丢弃所有前面的任务Cntl2[l],必定丢弃到第一个人。而第一个人丢弃的任务必定给了第二个人,因此,可以得到,第一个人完成l个任务的时候,操作数为Cnt1[l]+Cntl2[l];这时,第三个人一直是没有任务的。

当他要完成[1,r]个任务的时候,丢弃后面的任务Cntr2[r]必定丢弃给第三个人。而第三个人必定丢弃给第二个人。因此同理可以得到:第三个人完成r个任务的时候,操作数为Cnt3[r]+Cntr2[r];。这时,第一个人是一直没有任务的。

最后,枚举第一个人的任务数l。找到最小的操作数r加和,维护一下最小值即可。

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
      
#include<map>//unordered_map
#include<set>//multiset
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
 
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
      
const int MAXN=2e5+10;
//const int MAXM=10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)

int A[MAXN],B[MAXN],C[MAXN];
int Out1[MAXN],Out3[MAXN];
int Optl2[MAXN],Optr2[MAXN];
int n,k1,k2,k3;

int main(){
	while(~scanf("%d%d%d",&k1,&k2,&k3)){
		n=k1+k2+k3;
		for(int i=1;i<=k1;++i) scanf("%d",&A[i]);
		for(int i=1;i<=k2;++i) scanf("%d",&B[i]);
		for(int i=1;i<=k3;++i) scanf("%d",&C[i]);
		sort(A+1,A+1+k1);sort(B+1,B+1+k2);sort(C+1,C+1+k3);
		int cnt=k1;
		for(int i=0,j=1;i<=n;++i){//第一个人:[0,i]任务 
			while(j<=k1&&A[j]<=i) ++j,--cnt;
			Out1[i]=cnt;
		}
		cnt=k3;
		for(int i=n+1,j=k3;i>=1;--i){//第三个人:[i,n+1]任务 
			while(j>=1&&C[j]>=i) --j,--cnt;
			Out3[i]=cnt;
		}
//		for(int i=0;i<=n;++i) printf("%d ",Out1[i]);puts("");
//		for(int i=1;i<=n+1;++i) printf("%d ",Out3[i]);puts("");
		cnt=0;
		for(int i=1,j=1;i<=n;++i){//第二个人:[i,n] 凡是小于的都踢出去 
			while(j<=k2&&B[j]<i) ++j,++cnt;
			Optl2[i]=cnt+Out1[i];
		}
		cnt=0;
		for(int i=n,j=k2;i>=1;--i){//第二个人:[1,i] 凡是大于的都踢出去 
			while(j>=1&&B[j]>i) --j,++cnt;
			Optr2[i]=cnt+Out3[i];
		}
//		printf("mid l:");for(int i=1;i<=n;++i) printf("%d ",Optl2[i]);puts("");
//		printf("mid r:");for(int i=1;i<=n;++i) printf("%d ",Optr2[i]);puts("");
		for(int i=n-1;i>=1;--i){
			Optr2[i]=min(Optr2[i],Optr2[i+1]);
		}
		int ans=INF32;
		for(int i=1;i<=n;++i){
			ans=min(ans,Optl2[i]+Optr2[i]);
//			printf("ans=%d\n",ans);
		}printf("%d\n",ans);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值