BUPT计导第三次机考12.8数组+二分答案详解

坐标:BUPT;OJ:Excited OJ
%%%AK大佬,感觉这次AK的人均OI选手……
还是刷题不够Orzzzz

A.阿尔法乘积

  • 注意题目要求:非零的数相乘
  • 注意数据范围:应为long long而非int
  • 同时,使用printf函数时应用lldI64d
#include 
#include 
#include 
#include 
#include 
#define For(i,a,b) for (int i=(a); i<=(b); ++i)
typedef long long ll;

ll alpha(ll x)
{
	if (x/10==0)
		return x;
	else
	{
		ll sum=1;
		while (x!=0)
		{
			if (x%10!=0)
				sum*=x%10;
			x/=10;
		}
		return alpha(sum);
	}
}

int main()
{
	ll n;
	scanf("%lld",&n);
	printf("%lld",alpha(n));
	return 0;
}
//4018224312

PS:感觉这道递归考的不难,但是还是有细节的

B.贴邮票

“贴邮票” 这三个字让我一阵恶寒……但是这次并非三循环暴力解法

#include 
#include 
#include 
#include 
#include 
#define For(i,a,b) for (int i=(a); i<=(b); ++i)

void swap(int *a, int *b)
{
	int t=*a; *a=*b; *b=t;
}

void sort(int a[], int n)
{
	For(i,1,n-1)
	{
		For(j,i+1,n)
		{
			if (a[j]>a[i])
				swap(&a[j],&a[i]);
		}
	}
}

int main()
{
	int m,n;
	scanf("%d%d",&m,&n);
	int a[n];
	For(i,1,n)
		scanf("%d",&a[i]);
	sort(a,n);
	int cnt=0,sum=0;
	For(i,1,n)
	{
		sum+=a[i];
		cnt++;
		if (sum>=m)
			break;
	}
	printf("%d",cnt);
	return 0;
}
/*
100 5
10 20 30 40 50
*/

在此选择了选择排序的方法,其实只需每次求出最大值即可,算是贪心思想?
PS:好吧让我们期待下一次的贴邮票

C.打印方阵

#include 
#include 
#include 
#include 
#include 
#define For(i,a,b) for (int i=(a); i<=(b); ++i)

int main()
{
	int n;
	scanf("%d",&n);
	int a[n][n];
	int cnt=0;
	For(i,0,n-1)
	{
		int x=-1,y=i;
		while(x!=y)
		{
			x++;
			cnt++;
			a[y][x]=cnt;
		}
		while(y!=0)
		{
			y--;
			cnt++;
			a[y][x]=cnt;
		}
	}
	For(i,0,n-1)
	{
		For(j,0,n-1)
			printf("%d ",a[i][j]);
		printf("\n");
	}
	return 0;
}

PS:没什么技术含量,但是我把x、y打反了orz

D.大牌点

这个题我停止了思考……其实可以打的更简洁
(其实是一个multimap) 乱打就完了

update
打得实在是太丑了,重置了一下:

#include 
#include 
#define For(i,a,b) for (int i=(a); i<(b); ++i)

char card[]="3456789TJQKA2BR";
int num[]={1,1,1,2,2,2,3,3,4,5,6,8,10,15,20};
int len=15;	//¹²15¸öÔªËØ 

int main()
{
	int n;
	scanf("%d",&n);
	char a[n][25];
	For(i,0,n)
		scanf("%s",a[i]);
	int sum[n];
	For(i,0,n)
	{
		int s=strlen(a[i]);
		sum[i]=0;
		For(j,0,s)
			For(k,0,len)
				if (a[i][j]==card[k])
				{
					sum[i]+=num[k];
					break;
				}
	}
	For(i,0,n)
	{
		int max=0,t=0;
		For(j,0,n)
			if (sum[j]>max)
			{
				max=sum[j];
				t=j;
			}
		sum[t]=0;
		printf("%s\n",a[t]);
	}
	return 0;
}
/*
5
QQQ56AJR9Q
T5RJJJT82
RKT8J6QT5A
5T9RJ9J6B
9994A7QRBQ
*/

E.最大的最小值

“二分答案” 应该说是本题的正解,复杂度为 O(nlogn)
然而蒟蒻本蒻竟然一直在想分治……Orzzzzz

送上机考后在各个相似题打AC的代码↓

update
今晚打完了Atcoder想用这篇博客里的代码提交一下,结果发现这道题编译不给过,仔细一看原来打成了C++……
经过修改,C语言的版本也能A了,只是一些语法上的问题,不过还是放在下面,Cpp的那个版本也留着了

#include 
typedef long long ll;

int n,m,i;
int a[100005];

ll BinarySearch(ll l, ll r)
{
	if (l>r)
		return l;
	else
	{	
		ll sum=0, cnt=0, mid=(l+r)>>1;
		for (i=0; i<n; i++)
		{
			if ((sum+a[i])>mid)
				sum=a[i], cnt++;
			else
				sum+=a[i];
		}
   		if (cnt<m)
		   return BinarySearch(l,mid-1);
   		else
		   return BinarySearch(mid+1,r);
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	ll sum=0; int maxn=0;
	for (i=0; i<n; ++i)
	{
		scanf("%d",&a[i]);
		sum+=a[i];
		maxn=(maxn>a[i])?maxn:a[i];
	}
	printf("%lld",BinarySearch(maxn,sum));
	return 0;
}


以下为Cpp版本:

#include 
#include 
using namespace std;
typedef long long ll;
const ll N=1e5+5;

ll BinarySearch(ll, ll);
int n,m;
int a[N];

int main()
{
//	freopen("9.in","r",stdin);
	ios::sync_with_stdio(0);
	cin>>n>>m;
	ll sum=0; int maxn=0;
	for (int i=0; i<n; ++i)
	{
		cin>>a[i];
		sum+=a[i];
		maxn=max(a[i],maxn);
	}
	cout<<BinarySearch(maxn,sum);
//	fclose(stdin);
	return 0;
}

ll BinarySearch(ll l, ll r)
{
	if (l>r)
		return l;
	else
	{	
		ll sum=0, cnt=0, mid=(l+r)>>1;
		for (ll i=0; i<n; i++)
		{
			if ((sum+a[i])>mid)
				sum=a[i], cnt++;
			else
				sum+=a[i];
		}
   		if (cnt<m)
		   return BinarySearch(l,mid-1);
   		else
		   return BinarySearch(mid+1,r);
	}
}
/*
input:
7 5
100
400
300
100
500
101
400
output:
500

input:
23 7
4568
8417
7598
9710
1431
9731
7755
9039
524
8998
5861
963
6882
2463
6606
6459
8391
6558
6166
6786
4263
6593
2324
output:
22410
*/

以上是机考前两组测试数据(其他的太长了),自测的同学可以试试~~

PS:大佬扒出这是NOI训练题,遂又发现题源是USACO,我查了一下POJ也有此题,不愧为二分答案的经典题!!
(然而我并没有做过Orzzzz)

此题现在可在洛谷P1182、P2884进行测试

一开始我打的是以下代码,但可过USACO,洛谷那道不能过

ll BinarySearch(ll l, ll r)
{
	if (l==r)
		return l;
	else
	{	
		ll sum=0, cnt=0, mid=(l+r)>>1;
		for (ll i=0; i<n; i++)
		{
			if ((sum+a[i])>mid)
				sum=a[i], cnt++;
			else
				sum+=a[i];
		}
   		if (cnt<m)
		   return BinarySearch(l,mid);
   		else
		   return BinarySearch(mid+1,r);
	}
}

任何尾递归也都能改成迭代写法(仅用while实现),有兴趣的同学也不妨试试

欢迎大家交流、讨论! (^▽^)/❤

你可能感兴趣的:(作业)