Codeforces Round #574 (Div. 2)

Codeforces Round #574 (Div. 2)

比赛链接

这套题目比较简单,然而我才 (A)(4) 道题目,而且其中的一道题目赛后还调了很长时间。

A. Drinks Choosing

这道题目的困难在读题,读了 (20) 多分钟的题目还没读懂,后来去 (luogu) 看的翻译,直接贪心就可以了,先把可以凑成两个的填完,然后剩下的填 (1) 个的就可以了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+100;
int n,k;
int tp[N];
int main()
{
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		tp[x]++;
	}
	int mid=n/2;
	if (n%2==1) mid++;
	for (int i=1;i<=k;i++)
	if (tp[i]&&mid-tp[i]/2>=0)
	{
		mid-=tp[i]/2;
		tp[i]%=2;
	}
	for (int i=1;i<=k;i++)
	if (tp[i]&&mid-1>=0)
	{
		tp[i]=0;
		mid--;
	}
	int sum=0;
	for (int i=1;i<=k;i++)
	sum+=tp[i];
	printf("%d
",n-sum);
	return 0;
}

B. Sport Mafia

这道题直接枚举就可以了,看似是 (Theta (n)) 的复杂度,其实根据等差数列求和公式 (n*(n+1)/2) ,所以最坏时间复杂度是 (Theta (sqrt{n})) ,然后就可以过了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,k;
int main()
{
	scanf("%lld%lld",&n,&k);
	for (ll i=1;i<=n;i++)
	if (i*(i+1)/2-n+i==k)
	{
		printf("%lld
",n-i);
		return 0;
	}
	return 0;
}

C. Basketball Exercise

这道题目是一个比较简单的 (DP) ,转移只有三种情况,从上一列的不同颜色转移过来,从上上一列的两种颜色转移过来。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+100;
ll a[N][4],f[N][4];
int n;
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	scanf("%lld",a[i]+1);
	for (int i=1;i<=n;i++)
	scanf("%lld",a[i]+2);
	f[1][1]=a[1][1];
	f[1][2]=a[1][2];
	for (int i=2;i<=n;i++)
	{
		f[i][1]=f[i-1][2]+a[i][1];
		f[i][2]=f[i-1][1]+a[i][2];
		if (i>=3)
		{
			f[i][1]=max(max(f[i-2][1],f[i-2][2])+a[i][1],f[i][1]);
			f[i][2]=max(max(f[i-2][1],f[i-2][2])+a[i][2],f[i][2]);
		}
	}
	printf("%lld
",max(f[n][1],f[n][2]));
	return 0;
}

D. Submarine in the Rybinsk Sea

这题的简单版比较简单,直接按照每一位算贡献就可以了,每一个数第 (i)(x) 的贡献就是

[x*10^{i*2}*n+x*10^{i*2-1}*n ]

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+100,MOD=998244353;
int n;
ll a[N];
ll ans;
inline void work(ll x)
{
	int num=0;
	while (x)
	{
		ll will=pow(10,num*2);
		ans=(ans+((x%10)*will%MOD+((x%10)*will%MOD*10%MOD))*n%MOD)%MOD;
		x=x/10;
		++num;
	}
	return ;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	scanf("%lld",a+i);
	for (int i=1;i<=n;i++)
	work(a[i]);
	printf("%lld",ans);
	return 0;
}

困难版其实只需要修改一下就可以了,当一个数第 (i) 位有 (x*10^{i*2})(x*10^{i*2-1}) 时必须和这个数相同的位数或者大于这个数数位的数一起做 (f) 操作。

E. OpenStreetMap

这道题直接跑滑动窗口就可以了,每一行跑一遍,然后再在列上跑一遍就可以了。

#include<bits/stdc++.h>
#define ll long long
const int N=3e3+100;
using std::vector;
ll n,m,a,b,ans;
ll x,y,z;
ll g[N*N],h[N][N],minn[N][N];
vector<ll>v;
int main()
{
	scanf("%lld%lld%lld%lld",&n,&m,&a,&b);
	scanf("%lld%lld%lld%lld",&g[0],&x,&y,&z);
	for (int i=1;i<=N*N-100;i++)
	g[i]=(g[i-1]*x+y)%z;
	for (int i=1;i<=n;i++)
	for (int j=1;j<=m;j++)
	h[i][j]=g[(i-1)*m+j-1];
	for (int i=1;i<=n;i++) 
	{
		v.clear();
		for (int j=1;j<=m;j++)
		{
			while (!v.empty()&&h[i][v.back()]>h[i][j]) v.pop_back();
			v.push_back(j);
			if (!v.empty()&&v.front()<j-b+1) v.erase(v.begin(),v.begin()+1);
			if (j>=b) minn[j][i]=h[i][v.front()];
		}
	}
	for (int i=b;i<=m;i++)
	{
		v.clear();
		for (int j=1;j<=n;j++)
		{
			while (!v.empty()&&minn[i][v.back()]>minn[i][j]) v.pop_back();
			v.push_back(j);
			if (!v.empty()&&v.front()<j-a+1) v.erase(v.begin(),v.begin()+1);
			if (j>=a) ans+=minn[i][v.front()];
		}
	}
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/last-diary/p/11561752.html