Codeforces Round #834 (Div. 3)

Preface

我是水博客之王,Div3也能拿来水(我没把1hAK掉的校趣味赛搬过来写篇博客已经很克制了)

没什么好说的,因为是Unrated所以就打的很随意,结果最后一题结束后5min才过(刚开始想复杂了),还是没能AK


A. Yes-Yes?

SB题,WA了半天发现我的写法要特判\(n=1\)的情况,最后才交过

#include<cstdio>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=55;
int t; char s[N];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; scanf("%s",s+1); int n=strlen(s+1); bool flag=1;
		for (i=1;i<=n&&flag;++i) if (!(s[i]=='Y'||s[i]=='e'||s[i]=='s')) flag=0;
		for (i=2;i<n&&flag;++i)
		{
			if (s[i]=='Y')
			{
				if (s[i-1]!='s'||s[i+1]!='e') flag=0;
			} else if (s[i]=='e')
			{
				if (s[i-1]!='Y'||s[i+1]!='s') flag=0;
			} else
			{
				if (s[i-1]!='e'||s[i+1]!='Y') flag=0;
			}
		}
		if (n==1&&flag) { puts("YES"); continue; }
		if (s[1]=='Y')
		{
			if (s[2]!='e') flag=0;
		} else if (s[1]=='e')
		{
			if (s[2]!='s') flag=0;
		} else 
		{
			if (s[2]!='Y') flag=0;
		}
		if (s[n]=='Y')
		{
			if (s[n-1]!='s') flag=0;
		} else if (s[n]=='e')
		{
			if (s[n-1]!='Y') flag=0;
		} else 
		{
			if (s[n-1]!='e') flag=0;
		}
		puts(flag?"YES":"NO");
	}
}

B. Lost Permutation

又是SB题,感觉做这种题锻炼读题能力比锻炼写代码能力还多

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=2005;
int t,m,sum,b[N],s[N]; bool vis[N];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (i=1;i<=2000;++i) s[i]=s[i-1]+i;
	for (scanf("%d",&t);t;--t)
	{
		int mx=0,ret=0; for (i=1;i<=50;++i) vis[i]=0; bool sign=1;
		for (scanf("%d%d",&m,&sum),i=1;i<=m;++i)
		{
			scanf("%d",&b[i]); mx=max(mx,b[i]); ret+=b[i];
			if (vis[b[i]]) sign=0; vis[b[i]]=1;
		}
		if (!sign) { puts("YES"); continue; }
		bool flag=0; for (i=mx;s[i]-ret<=sum&&!flag;++i) if (s[i]-ret==sum) flag=1;
		puts(flag?"YES":"NO");
	}
}

C. Thermostat

细节分类讨论题

不难发现答案只有\(-1,0,1,2,3\),注意\(2\)\(3\)的区别,总之比较锻炼逻辑的严密性

#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
int t,l,r,x,a,b;
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		scanf("%d%d%d%d%d",&l,&r,&x,&a,&b);
		if (a==b) { puts("0"); continue; }
		if (b<l||b>r) { puts("-1"); continue; }
		if (l<=a&&a<=r)
		{
			if (abs(a-b)>=x) { puts("1"); continue; }
			if (max(abs(l-b),abs(r-b))<x) { puts("-1"); continue; }
			if (min(abs(l-b),abs(r-b))>=x) { puts("2"); continue; }
			if (abs(l-b)>=x)
			{
				if (abs(l-a)>=x) { puts("2"); continue; }
				else if (abs(r-a)>=x)
				{
					puts("3"); continue; 
				} else { puts("-1"); continue; }
			} else
			{
				if (abs(r-a)>=x) { puts("2"); continue; }
				else if (abs(l-a)>=x)
				{
					puts("3"); continue;
				} else { puts("-1"); continue; }
			}
		}
		if (max(abs(l-a),abs(r-a))<x) { puts("-1"); continue; }
		if (abs(a-b)>=x) { puts("1"); continue; }
		if (a<l)
		{
			if (abs(r-b)>=x) puts("2"); else puts("-1");
		} else
		{
			if (abs(l-b)>=x) puts("2"); else puts("-1");
		}
	}
}

D. Make It Round

根据某个经典结论,我们知道一个数末尾的\(0\)的个数只和其分解后\(2\)\(5\)的个数有关

因此考虑求出\(n\)分解后\(2\)的个数\(t_2\)\(5\)的个数\(t_5\),考虑先去掉它后面本来的\(0\),这样\(t_2,t_5\)中至多只有一个不为\(0\)

然后先考虑在\(k\)里面乘上对应的\(2\)或者\(5\),直到溢出或者\(n\)中的对应剩余个数不够了

接下来如果能给\(k\)\(10\)就乘,不过注意最后要输入最大的那个,判断下\(2\sim 9\)中最大可以乘上的是哪个即可

喜闻乐见的要注意中间会爆long long

#include<cstdio>
#include<iostream>
#include<algorithm>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
int t,n,m;
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%lld",&t);t;--t)
	{
		scanf("%lld%lld",&n,&m); int t2=0,t5=0,t=n; long long ans=n;
		while (t%2==0) ++t2,t/=2; while (t%5==0) ++t5,t/=5;
		int det=min(t2,t5); t2-=det; t5-=det; int cur=1;
		while (t2&&cur*5<=m) --t2,cur*=5,ans*=5;
		while (t5&&cur*2<=m) --t5,cur*=2,ans*=2;
		while (cur*10<=m) cur*=10,ans*=10;
		if (ans%10!=0) { printf("%lld\n",1LL*n*m); continue; }
		for (RI i=9;i>1;--i) if (cur*i<=m) { cur*=i; ans*=i; break; }
		printf("%lld\n",ans);
	}
	return 0;
}

E. The Humanoid

刚开始做完D点到F了,没看到这个大水题

考虑如果固定了乘法的使用顺序,那我们显然可以直接贪心,把人从小到大击败即可

如果遇到打不过的就嗑药,不难证明这样一定是最优的

那么乘\(3\)的药到底在什么时候用呢,管那么多干嘛,一共就三种情况直接枚举就好了

#include<cstdio>
#include<iostream>
#include<algorithm>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int t,n,h,a[N],c[3],ans;
inline int solve(void)
{
	int tmp=h,p=0,ret=0; for (RI i=1;i<=n;++i)
	{
		if (tmp>a[i]) { ++ret; tmp+=a[i]/2; continue; }
		while (tmp<=a[i]&&p<3) tmp*=c[p++];
		if (tmp>a[i]) ++ret,tmp+=a[i]/2; else break;
	}
	return ret;
}
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%lld",&t);t;--t)
	{
		RI i,j; for (scanf("%lld%lld",&n,&h),i=1;i<=n;++i) scanf("%lld",&a[i]);
		for (sort(a+1,a+n+1),ans=i=0;i<3;++i)
		{
			for (j=0;j<3;++j) c[j]=2; c[i]=3; ans=max(ans,solve());
		}
		printf("%lld\n",ans);
	}
	return 0;
}

F. All Possible Digits

首先不难发现每次肯定操作最新产生的那个数,而且我们发现操作次数肯定不会超过\(p\)

那么就意味着最多只有一次进位操作,我们考虑先求出所有数字中没有出现过的最大数字\(q\)

根据\(q\)\(a_n\)的大小关系分情况讨论即可,进位的话直接暴力即可

#include<cstdio>
#include<iostream>
#include<set>
#define RI register int
#define CI const int&
using namespace std;
const int N=105;
int t,n,p,a[N],ans; set <int> s;
inline void updata(void)
{
	a[n]=0; s.insert(0); if (++a[n-1]<p) s.insert(a[n-1]);
	for (RI i=n-1;i>=1;--i) if (a[i]==p)
	if (a[i]=0,++a[i-1]<p) s.insert(a[i-1]);
}	
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d%d",&n,&p),s.clear(),ans=0,i=1;i<=n;++i)
		scanf("%d",&a[i]),s.insert(a[i]); a[0]=0;
		if (s.size()==p) { puts("0"); continue; }
		int mx=p-1; while (s.count(mx)) --mx;
		int mi=0; while (s.count(mi)) ++mi;
		if (mx>=a[n])
		{
			ans=mx-a[n]; if (mi>a[n]) { printf("%d\n",ans); continue; }
			ans+=p-mx; int tmp=a[n]; updata();
			int mi=0; while (s.count(mi)) ++mi;
			if (mi>tmp) { printf("%d\n",ans); continue; }
			int mx=tmp; while (s.count(mx)) --mx;
			ans+=mx-a[n]; printf("%d\n",ans); continue;
		} else
		{
			ans=p-a[n]; updata();
			if (s.size()==p) { printf("%d\n",ans); continue; }
			int mx=p-1; while (s.count(mx)) --mx;
			ans+=mx-a[n]; printf("%d\n",ans);
		}
	}
	return 0;
}

G. Restore the Permutation

刚开始没想到倒着做去写线段树+二分了,其实直接倒着做就行了

如果我们正着做,对于每个已经确定的最大值,要在所有小于它的未出现的数中挑一个尽量小

因为不仅要满足字典序最小还要让后面的数不至于找不到比它小的配对,但这样检验就很麻烦

所以直接考虑从后往前处理每个数,此时直接在未出现的数里选它的前驱即可,清楚又好写

#include<cstdio>
#include<algorithm>
#include<set>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005,INF=1e9;
int t,n,ans[N],b[N]; bool vis[N]; set <int> s;
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d",&n),i=1;i<=n;++i) vis[i]=0;
		bool flag=1; for (n>>=1,i=1;i<=n;++i)
		if (scanf("%d",&b[i]),vis[b[i]]) flag=0; else vis[b[i]]=1;
		if (!flag) { puts("-1"); continue; }
		for (s.clear(),i=1;i<=n*2;++i) if (!vis[i]) s.insert(i);
		for (s.insert(-INF),i=n;i>=1;--i)
		{
			int tmp=*--s.lower_bound(b[i]);
			if (tmp!=-INF) ans[2*i-1]=tmp,ans[2*i]=b[i],s.erase(tmp); else { flag=0; break; }
		}
		if (!flag) { puts("-1"); continue; }
		for (i=1;i<=n*2;++i) printf("%d%c",ans[i]," \n"[i==n*2]);
	}
	return 0;
}

Postscript

话说这周五的Div2什么鬼,11:30开始,这不是直接打到凌晨2点了……

身体顶不太住啊,周六的混合场倒是可以冲一把

posted @ 2022-11-21 20:24  空気力学の詩  阅读(85)  评论(0编辑  收藏  举报