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

158 阅读5分钟

比赛链接

A

思路

选一个移动xx步即可,注意距离最大为n1n-1的限制。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
	puts("");
}
void solve()
{
	ll n,x,a,b;
	In(4,&n,&x,&a,&b);
	if(a>b)
		swap(a,b);
	ll ans=min(n-1ll,b-(a-x));
	Out(1,ans);
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}
}

B

思路

第一种操作可以使当前数字变大,第二种操作是变小,因为第二种操作每次都减11,因此只要得到一个比yy大的数字就一定可以得到yy。观察发现当xx最小为44时可以通过操作得到一个无限大的数,因此只需要特判x<3x<3时的情况即可。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
	puts("");
}
void solve()
{
	ll x,y,cnt=0;
	In(2,&x,&y);
	if(x>=4)
		puts("YES");
	else if(x==1 && y>1)
		puts("NO");
	else if(x==2 && y>3)
		puts("NO");
	else if(x==3 && y>3)
		puts("NO");
	else
		puts("YES");
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}
}

C

思路

最终得到的序列必定有且只有一个元素出现过两次,其他元素仅出现一次,维护相同元素的最近距离即可。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
	puts("");
}
const int N=2E5+10;
ll vis[N];
void solve()
{
	ll n;
	In(1,&n);
	rep(i,1,n)
		vis[i]=0;
	ll x;
	ll ans=LLM;
	rep(i,1,n)
	{
		In(1,&x);
		if(vis[x])
			ans=min(ans,i-vis[x]+1);
		vis[x]=i;
	}
	if(ans==LLM)
		ans=-1;
	Out(1,ans);
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}
}

D

思路

考虑两个耐力相同的英雄,肯定是留下能力最强的一个。每次打怪都尽可能多地打,因为如果这一天有一只怪本来能打却没有打,那么它不仅会消耗第二天英雄的耐力,还有可能卡住能力上限使我们不能挑耐力好一点但是能力低的英雄获得更优解。
考虑一天最多能打几只。如果只打一只,我们可以从所有耐力值不小于11的英雄中选一个能力值足够的来打,如果继续打第二只,就需要存在一个英雄耐力值不小于22且能力值足够。我们发现如果一天要打xx只怪,就需要所有耐力值不小于xx的英雄能力值至少为这些怪物的最大值。
因此设f[i]f[i]为耐力至少为ii的英雄的最大能力值,然后模拟打怪过程,每天枚举ff的下标(即今天打多少只怪),看对应的ff值是否满足能力值要求。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const int N=2E5+10;
ll n,m;
ll a[N],f[N];
void print()
{
	rep(i,1,n)
		Out_(1,f[i]);
	puts("");
}
void solve()
{
	ll ans=0;
	In(1,&n);
	rep(i,1,n)
	{
		f[i]=0;
		In(1,&a[i]);
	}
	In(1,&m);
	rep(i,1,m)
	{
		ll p,s;
		In(2,&p,&s);
		f[s]=max(f[s],p);
	}
	for(int i=n-1;i>=1;--i)
		f[i]=max(f[i],f[i+1]);
	ll cur=1;
	f[0]=f[1];
	while(cur<=n)
	{
		ll end=cur;
		ll maxi=0;
		while(end<=n && f[end-cur+1]>=a[end] && f[end-cur+1]>=maxi)
		{
			maxi=max(maxi,a[end]);
			++end;
		}
		--end;
		if(end<cur)
		{
			ans=-1;
			break;
		}
		++ans;
		cur=end+1;
	}
	Out(1,ans);
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}
}

E

思路

从只有两个人的情况找规律,然后拓展到三个人。这条博客讲得很详细。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const int N=2E5+10;
ll k1,k2,k3,n;
ll cnt1[N],cnt2[N],cnt3[N],mini[N];
int main()
{
	In(3,&k1,&k2,&k3);
	n=k1+k2+k3;
	rep(i,1,k1)
	{
		ll tmp;
		In(1,&tmp);
		++cnt1[tmp];
	}
	rep(i,1,k2)
	{
		ll tmp;
		In(1,&tmp);
		++cnt2[tmp];
	}
	rep(i,1,k3)
	{
		ll tmp;
		In(1,&tmp);
		++cnt3[tmp];
	}
	rep(i,1,n)
	{
		cnt1[i]+=cnt1[i-1];
		cnt2[i]+=cnt2[i-1];
		cnt3[i]+=cnt3[i-1];
	}
	mini[n+1]=LLM;
	for(int i=n;i>=0;--i)
	{
		mini[i]=min(mini[i+1],cnt3[i]-cnt2[i]);
	}
	ll ans=LLM;
	rep(i,0,n)
	{
		ans=min(ans,cnt2[i]-cnt1[i]+mini[i]);
	}
	ans+=cnt1[n]+cnt2[n];
	Out(1,ans);
}

F

思路

2302^{30}枚举必然超时,考虑如何优化。两个数字11的数目相同,必有这两个数字前151511的数目之差与后151511的数目之差互为相反数。考虑以a1a_1为基准,只要所有数字11的数目都和a1a_1相同,那么所有数字11的数目就都相同了。因此分别枚举答案的前1515位和后1515位,将前1515位异或后得到的b2b1,b3b1,,bnb1b_2-b_1,b_3-b_1,\cdots ,b_n-b_1存在vectorvector中,用mapmap维护某个vectorvector是否出现过。只要在枚举后1515位时出现了一个恰好符号相反的vectorvector(其实只需要把式子换成b1b2,b1b3,,b1bnb_1-b_2,b_1-b_3,\cdots ,b_1-b_n并在mapmap中查询),就说明找到了答案,将前1515位和后1515位拼起来即可。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
ll ct(ll o)
{
	register ll ret=0,x=o,t;
	while(x)
	{
		t=x&-x;
		x-=t;
		++ret;
	}
	return ret;
}
const ll N=105;
ll n;
ll l[N],h[N],cnt[(1<<15)+10];
map<vector<ll>,ll> ma;
int main()
{
	In(1,&n);
	rep(i,1,n)
	{
		ll tmp;
		In(1,&tmp);
		l[i]=tmp&((1<<15)-1);
		h[i]=tmp>>15;
	}
	ll lim=(1<<15)-1;
	rep(i,0,lim)
	{
		ll v=i;
		while(v)
		{
			if(v&1)
				++cnt[i];
			v>>=1;
		}
	}
	rep(x,0,lim)
	{
		vector<ll> tmp;
		tmp.clear();
		ll fir=cnt[l[1]^x];
		rep(i,2,n)
		{
			tmp.push_back(fir-cnt[l[i]^x]);
		}
		ma.insert(ma.end(),make_pair(tmp,x));
	}
	rep(x,0,lim)
	{
		vector<ll> tmp;
		tmp.clear();
		ll fir=cnt[h[1]^x];
		rep(i,2,n)
		{
			tmp.push_back(cnt[h[i]^x]-fir);
		}
		if(ma.find(tmp)!=ma.end())
		{
			Out(1,(x<<15)+ma[tmp]);
			return 0;
		}
	}
	Out(1,-1ll);
}