【纪中2020.5.06日】模拟赛题解

目录:

T1:移动奶牛
T2:电压放大器
T3:步行
T4:数数

第一题USACO 后三题是市选……

正题:

T1:移动奶牛

题目描述

Farmer John的三头获奖奶牛Bessie、Elsie和Mildred,总是会迷路走到农场上遥远的地方去!他需要你帮助将她们一起赶回来。
农场的草地大体是一块狭长的区域——我们可以将其想象成一条数轴,奶牛可以占据数轴上的任意整数位置。这3头奶牛现在正位于不同的整数位置,Farmer John想要移动她们,使得她们占据三个相邻的位置(例如,位置6、7、8)。
不幸的是,奶牛们现在很困,Farmer John要让她们集中精力听从命令移动并不容易。任意时刻,他只能使得一头处在“端点”(在所有奶牛中位置最小或最大)位置的奶牛移动。当他移动奶牛时,他可以命令她走到任意一个未被占用的整数位置,只要在新的位置上她不再是一个端点。可以看到随着时间的推移,这样的移动可以使奶牛们趋向越来越近。
请求出使得奶牛们集中到相邻位置所进行的移动次数的最小和最大可能值。

输入

输入包含一行,包括三个空格分隔的整数,为Bessie、Elsie和Mildred的位置。每个位置均为一个范围1…10^9内的整数。

输出

输出的第一行包含Farmer John需要将奶牛们聚集起来所需进行的最小移动次数。第二行包含他将奶牛聚集起来能够进行的最大移动次数。

样例输入

4 7 9

样例输出

1
2

分析:

大意就是
将位于数轴上的三个正整数点 通过若干次操作变成三个相邻的点 每次操作只能将位于两端的一个点置于另两个点之间 求最少及最多次数
所以 模拟就好了
也可以找规律

CODE:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> 
using namespace std; 
int a[100005],x=0;
int getmin(){  //找最小次数
	if((a[3-2]-a[0]==3-2&&a[3-1]-a[3-2]>2)||(a[3-1]-a[1]==3-2&&a[1]-a[0]>2))
		return 2;
	int j=0;
	for(int i=0;i<3;i++){
    	while(j<3-1&&a[j+1]-a[i]<=3-1)
			j++;
    	x=max(x,j-i+1);
	}
	return 3-x;
}
int getmax(){  
	return max(a[3-2]-a[0],a[3-1]-a[1])-3+2;  //最大次数
}
int main(){
	freopen("herding.in","r",stdin);
	freopen("herding.out","w",stdout);
	for(int i=0;i<3;i++)
		scanf("%d",&a[i]);
	sort(a,a+3);  //排序
	printf("%d\n%d\n",getmin(),getmax());
	return 0;
}

T2:电压放大器

题目描述

西西需要把输入的电压1伏通过一系列电压放大器放大成原来的N倍,然后输出。
西西现在手上有两种放大器:
第一种能够把X伏的电压放大成2X-1伏
第二种能够把X伏的电压放大成2X+1伏
放大器是串联(即按顺序放在一条线路上)的。
现在西西手上有用不完的放大器,他希望能组出一个电路,使用数量最少的放大器,使得电压被放大了刚好N倍。

输入

一行一个正整数N(1<=N<=2*10^9)

输出

如果无法组成电路则输出一行No solution
否则输出两行,第一行一个整数表示最少的放大器个数K,第二行K个用空格隔开的1或2,表示放大器序列。1表示第一种,2表示第二种,其中左边为输入端。如果有多解输出任意一组。

样例输入

5

样例输出

2
2 1

分析:

大意就是
给你一个1 让你经过多次操作 分两种:2x+12x−1 变为n这个数 求最少要多少步 并输出操作序号
分析奇偶性 你会发现无论如何得到的结果都是奇数 所以如果是偶数直接return 0
奆佬们提示说:
1 3 5 7 9 11 13 17 19……
+1 -1 +1 -1 +1 -1 +1 -1……
判断项数 偶数就(x−1)/2否则就 (x+1)/2

CODE:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
long long n,m,ans[10010],i;
int main()
{
    freopen("amp.in","r",stdin);
	freopen("amp.out","w",stdout);
    cin>>n;
    if(n%2==0)  //不存在
    {
     	cout<<"No solution";
     	return 0;
    }
    else
    {
     	while(n!=1)
     	{
     	 	i++,m=n/2;
     	 	if(m%2!=0) //判断奇偶
     	 	  n=m,ans[i]=2;
     	 	else
     	 	  n=m+1,ans[i]=1;
     	}
    }
    cout<<i<<endl;
    for(int j=i;j>=1;j--)
	   cout<<ans[j]<<" ";
	return 0;
}

T3:步行

题目描述

ftiasch 又开发了一个奇怪的游戏,这个游戏是这样的:有N 个格子排成一列,每个格子上有一个数字,第i 个格子的数字记为Ai。这个游戏有2 种操作:

  1. 如果现在在第i 个格子,则可以跳到第Ai 个格子。

  2. 把某个Ai 增加或减少1。

nm 开始在第1 个格子,他需要走到第N 个格子才能通关。现在他已经头昏脑涨啦,需要你帮助他求出,从起点到终点最少需要多少次操作。

输入

第1 行,1 个整数N。
第2 行,N 个整数Ai。

输出

1 行,1 个整数,表示最少的操作次数。

样例输入

5
3 4 2 5 3

样例输出

3

分析:

BFS
a[i] 我们可以对 a[a[i]] a[a[i]−1] a[a[i]+1] 进行更新

CODE:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,i,j,a[100010],b[100010],c[100010],d[100010];
int main()
{
	freopen("walk.in","r",stdin);
    freopen("walk.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    	scanf("%d",&a[i]);
    b[1]=a[1];
    c[1]=1;
    d[1]=d[a[1]]=1;
    i=0,j=1;
	while(i<j)  //BFS
	{
		i++;
		if(!d[a[b[i]]])  //以上三种情况
		{
			j++;
			b[j]=a[b[i]];
			c[j]=c[i]+1;
			d[b[j]]=1;
			if(b[j]==n)
            {
                printf("%d\n",c[j]);
                return 0;
            }
		}
		if(!d[b[i]-1])
		{
			j++;
			b[j]=b[i]-1;
			c[j]=c[i]+1;
			d[b[j]]=1;
			if(b[j]==n)
            {
                printf("%d\n",c[j]);
                return 0;
            }
		}
		if(!d[b[i]+1])
		{
			j++;
			b[j]=b[i]+1;
			c[j]=c[i]+1;
			d[b[j]]=1;
			if(b[j]==n)
            {
                printf("%d\n",c[j]);
                return 0;
            }
		}
	}
}

T4:数数

这道题几个月前一次模拟赛做过了
写过题解 是个三维DP
题解传送门(第三题)

猜你喜欢

转载自blog.csdn.net/dgssl_xhy/article/details/107138916