[CF1036X]Educational Codeforces Round 50 (Rated for Div. 2)

Posted by Dispwnl on September 8, 2018

edu场上分啦233

A  Function Height

题目大意

给你$(0,0)$到$(2n,0)$这$2n+1$个点,其中奇数点的$y$可以调整

将点与下一个点之间连线,要使与$x$轴构成的图形面积正好为$k$,求点中最大的$y$的最小值

题解

构成了许多三角形,每个的面积为$y$值,所以答案为$\lceil\frac{k}{n}\rceil$(不足面积就整体$+1$,超过面积不用管,因为可以把部分$y$变小)

代码

# include<bits/stdc++.h>
# define LL long long
using namespace std;
LL n,k;
int main()
{
	cin>>n>>k;
	LL ans=k/n;
	if(ans*n<k) ++ans;
	cout<<ans;
	return 0;
}

B  Diagonal Walking v.2

题目大意

一个点,初始在$(0,0)$,每次可以直着或者斜着走一步,要求正好$k$步走到给定点,问斜着走的最大步数是多少

题解

首先$k<max(n,m)$是绝对走不到目标点的

先考虑$n=m$的对角线做法

  • 假设$n$和$k$奇偶性相同,直接走对角线就是最优的方法且一定能走到目标点,因为多了的部分可以通过折返走消掉
  • 假设$n$和$k$奇偶性不同,可以通过先走到$(1,1)$来变成奇偶性相同的情况,如图

若$n!=m$,我们可以先向$n,m$中比较大的方向走一段,然后就构成了$n=m$的对角线情况

还是分$n,m$的奇偶性考虑,设$x=max(n,m)-min(n,m)$

  • 若$n,m$的奇偶性相同,$x$肯定是偶数,所以两个格子分解成两个斜步走就行了
  • 若$n,m$的奇偶性不同,$x$肯定为奇数,所以前面两个格子走两个斜步,最后一个格子走直步就行了

代码

# include<bits/stdc++.h>
# define LL long long
using namespace std;
LL q,k,n,m;
int main()
{
	cin>>q;
	while(q--)
	{
		cin>>n>>m>>k;
		if(k<max(n,m)) cout<<-1<<endl;
		else if(n%2!=m%2) cout<<k-1<<endl;
		else
		{
			if((k-min(n,m))%2==0) cout<<k<<endl;
			else cout<<k-2<<endl;
		}
	}
	return 0;
}

C  Classy Numbers

题目大意

给你一个范围$[L,R]$,求这个范围里每一位非零数字的个数和不大于3的数字个数

题解

一个简单的数位$dp$,结果为$ans_r-ans_{l-1}$

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
# define LL long long
using namespace std;
int T,num;
LL L,R,Ans1,Ans2;
LL ln[19];
LL f[19][4];
void GET_POS(LL x)
{
	while(x) ln[++num]=x%10,x/=10;
}
LL dfs(int l=num,int r=0,bool fl=1)
{
	if(r>3) return 0;
	if(!l) return 1;
	if(!fl&&f[l][r]!=-1) return f[l][r];
	int lim=fl?ln[l]:9;
	LL Ans=0;
	for(int i=0;i<=lim;++i)
	  Ans+=dfs(l-1,r+(i!=0),fl&&i==ln[l]);
	if(!fl) f[l][r]=Ans;
	return Ans;
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		cin>>L>>R;
		memset(f,-1,sizeof(f));
		num=0,GET_POS(R),Ans1=dfs();
		num=0,GET_POS(L-1),Ans2=dfs();
		cout<<Ans1-Ans2<<endl;
	}
	return 0;
}

D  Vasya and Arrays

题目大意

给你两个序列,每次可以选择一个序列的连续一部分合并,若不可以使两个序列相同输出$-1$,否则输出满足条件的情况下最后序列的最长长度

题解

开始用$cin$读入T了一发…

发现可以贪心,搞两个指针,同时维护两个序列的前缀和,每次比较两个前缀和,哪个小哪个指针就往后移,相同就两个指针同时向后移,最后看两个序列长度是否相同就好了

代码

# include<bits/stdc++.h>
# define LL long long
using namespace std;
const int MAX=3e5+1;
LL n,m,sum1,sum2;
LL a[MAX],b[MAX];
int main()
{
	scanf("%I64d",&n);
	for(int i=1;i<=n;++i)
	  scanf("%I64d",&a[i]);
	scanf("%I64d",&m);
	for(int i=1;i<=m;++i)
	  scanf("%I64d",&b[i]);
	int l=1,r=1,N=n,M=m;
	sum1=a[1],sum2=b[1];
	while(l<=n&&r<=m)
	{
		if(sum1<sum2) sum1+=a[++l],--N;
		else if(sum1>sum2) sum2+=b[++r],--M;
		else sum1+=a[++l],sum2+=b[++r];
	}
	if(N!=M) cout<<-1;
	else cout<<N;
	return 0;
}