2020年10月29日普及组

题号题目名称
A捡石头
B魔法药水
C土地恢复
D组合数
E排数字
F小武的方程

A:

题目描述

地上有2N个石头,排成了一条线,相邻的石头距离为1,石头之间有着不同的大小,有N种大小不同 的石头,即相同大小的石头有2个,现将石头按照从小到大的顺序依次编号为1到N,有2个石头共享 相同的编号,现在小武和小林要同时从最左边的石头出发,按照石头大小依次捡起编号为1到N的石 头,并且相同编号的石头同一个人只能捡起来一次,现在他们想把地上的石头都捡完,求两个人的行 走的最短距离和为多少?

输入格式

第一行一个正整数N 第二行2N个数,按照石头从左到右的顺序依次给出石头的编号

输出格式

一行一个数表示行走的最短距离和

正题:

我们先用桶来记录每个石子的位置,然后分类讨论:

  1. 小武走到第一个,小林走到第二个
  2. 小武走到第二个,小林走到第一个
    来自Jackma_mayichao
    来自Jackma_mayichao

那么转移方程就是:

a n s + = m i n ( a b s ( a [ i + 1 ] [ 1 ] − a [ i ] [ 1 ] ) + a b s ( a [ i + 1 ] [ 2 ] − a [ i ] [ 2 ] ) , a b s ( a [ i + 1 ] [ 2 ] − a [ i ] [ 1 ] ) + a b s ( a [ i + 1 ] [ 1 ] − a [ i ] [ 2 ] ) ) ans+=min(abs(a[i+1][1]-a[i][1])+abs(a[i+1][2]-a[i][2]),abs(a[i+1][2]-a[i][1])+abs(a[i+1][1]-a[i][2])) ans+=min(abs(a[i+1][1]a[i][1])+abs(a[i+1][2]a[i][2]),abs(a[i+1][2]a[i][1])+abs(a[i+1][1]a[i][2]))

#include<iostream>
#include<cstdio>
#include<cmath> 
using namespace std;
int n;
int a[1001010][3];
int main()
{
	scanf("%d", &n);
	for(int i=1; i<=n*2; i++)
	{
		int x;
		scanf("%d", &x);
		a[x][0]++;
		a[x][a[x][0]]=i;
	}
	int ans=a[1][1]+a[1][2]-2;
	for(int i=1; i<n; i++)
		ans+=min(abs(a[i+1][1]-a[i][1])+abs(a[i+1][2]-a[i][2]),abs(a[i+1][2]-a[i][1])+abs(a[i+1][1]-a[i][2]));
	printf("%d", ans);
	return 0;
}

B:

题目描述

小武的实验室里有一种魔法药水,这个药水有个很奇怪的性质,它只能在盛放的体积为2的幂次时保 持稳定,例如1,2,4,8。所以小武在实验室里放置了很多容积为2的幂次的瓶子,其中N瓶放有魔法药 水,第i瓶魔法药水的体积为2的L[i]次方。这天小武想要收拾一下实验室,小武想知道最少用多少个瓶 子能把实验室的药水装完。
假设小武有任意2的幂次容积的瓶子,并且每种瓶子的数量足够使用。

输入格式

第一行一个正整数N
第二行N个数,表示L[i]

输出格式

一行一个数表示最少需要多少个瓶子

正题:

这题我们开一个桶来记录它当前次幂的数量,然后没两个可以凑成一个更大的

#include<iostream>
#include<cstdio>
using namespace std;
int n;
int a[1001000];
int main()
{
	scanf("%d", &n);
	for(int i=1; i<=n; i++)
	{
		int x;
		scanf("%d", &x);
		a[x]++;
	}
	long long sum=0;
	for(int i=0; i<1001000; i++)
	{
		if(a[i]==1)
			sum++;
		else
		if(a[i]!=0)
		{
			a[i+1]+=a[i]/2;
			sum+=a[i]%2;
		}
	}
	printf("%lld", sum);
	return 0;
}

C:

题目描述

宣文胜的家乡山西省是我国的产煤大省,因为长期挖煤导致了他家乡的某些地方出现了地陷的情况。 近几年国家大力开展环境整治和土地复耕,让人民不仅享受经济发展所带来的红利更要还老百姓绿水 青山。为了把这些地陷的土地恢复平整,他的家乡决定聘请他负责这项工作。

他负责恢复的是一条长度为n的土地,恢复土地的主要工作是填平下陷的地表。需要恢复的土地可以 看作是n块首尾相连的区域,一开始,第i块区域下陷的深度为di。宣文胜决定每天选择一段连续区间 [M, N] ,填充这段区间中的每块区域,让其下陷深度减少1。在选择区间时,需要保证,区间内的每 块区域在恢复前下陷深度均不为0 。

宣文胜希望你能帮他设计一种方案,可以在最短的时间内将整块土地的下陷深度都变为0。

输入格式

第一行输入一个整数n,表示恢复土地的长度。
第二行n个整数di,以空格隔开。

输出格式

输出一个整数,即最少需要多少天才能完成任务。

正题:

这题用贪心,每次找到一个比前一个数大的就相当于重新开一个坑,于是就把它们的差加上

#include<iostream>
#include<cstdio>
using namespace std;
long long n;
long long a[1001000];
int main()
{
	scanf("%lld", &n);
	long long last=0, sum=0;
	for(long long i=1; i<=n; i++)
	{
		scanf("%lld", &a[i]);
		if(a[i]>last)
			sum+=a[i]-last;
		last=a[i];
	}
	printf("%lld", sum);
	return 0;
} 

D:

在这里插入图片描述

正题:

预处理杨辉三角,每次转移时把相加后的值对k取模,用二维前缀和记录。

#include<iostream>
#include<cstdio>
using namespace std;
long long t, k;
long long a[2020][2020];
long long b[2020][2020];
void sandwich()
{
	a[1][1]=1;
	a[2][1]=1;
	a[2][2]=1;
	for(long long i=3; i<=2010; i++)
	{
		a[i][1]=a[i][i]=1;
		b[i][1]+=b[i-1][1]+b[i][0]-b[i-1][0];
		for(long long j=2; j<i; j++)
		{
			a[i][j]=(a[i-1][j]+a[i-1][j-1])%k;
			if(a[i][j]==0)
				b[i][j]=1;
			b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
		}
		for(long long j=i; j<=2010; j++)
			b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
	}
}
int main()
{
	scanf("%lld%lld", &t, &k);
	sandwich();
	while(t--)
	{
		long long n, m;
		scanf("%lld%lld", &n, &m);
		printf("%lld\n", b[n+1][min(n, m)+1]);
	}
	return 0;
}

E:

题目描述

小武有n个数字,这天小武想将数字理的顺一点,小武要把数字分组,每组的个数都是m,并且这m个 数字连续,小武想知道可以做到吗?

输入格式

第一行一个整数t表示数据组数 对于每组数据, 第一行两个整数n,m 第二行N个非负整数,表示数字

输出格式

如果可以做到输出“true”,否则输出“false”

正题:

用贪心的思想,每次找到一个没选的数,看以它开头能不能凑,如果不能就直接false

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n, m;
int a[100100];
bool f[10001];
int main()
{
	int t;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d%d", &n, &m);
		for(int i=1; i<=n; i++)
			scanf("%d", &a[i]);
		sort(a+1, a+1+n);
		if(n%m!=0)
		{
			printf("false\n");
			continue;	
		}
		int begin=0;
		int flag=1;
		for(int i=1; i<=n/m; i++)
		{
			if(flag==0)
				break;
			int j=begin+1;
			int k=a[j];
			f[j]=1;
			int s=1;
			int t=0;
			while(j<n&&s<m)
			{
				j++;
				if(f[j]==1)
				{
					if(a[j]-k>1)
					{
						flag=0;
						break;
					}
				}
				else
				{
					if(a[j]-k>1)
					{
						flag=0;
						break;
					}
					else
					if(a[j]-k==1)
					{
						f[j]=1;
						s++;
						k=a[j];
					}
					else
					if(a[j]==k&&t==0)
					{
						t=1;
						begin=j-1;
					}
				}
			}
			if(t==0)
				begin=j;
			if(s!=m)
			{
				flag=0;
				break;
			}
		}
		if(flag==0)
			printf("false\n");
		else printf("true\n");
		memset(f, 0, sizeof(f));
	}
}

E:

题目描述

小武有2个方程,x|y=A,x+y=B,其中|为二进制或符号,x和y是未知数,A和B已知,小武想知道这个 方程是否有非负整数解。

输入格式

第一行一个整数T表示数据组数
接下来T行,每行两个数A和B

输出格式

T行,
若方程有解输出Possible,否则输出Impossible

正题:

我们直接让x等于A,那么B-A就是y的值(在满足第二个条件的情况下)
这时就让A和B-A异或一下,看等不等与A就可以了

 #include<bits/stdc++.h>
 using namespace std;
 int t;
 int main()
 {
 	scanf("%d", &t);
 	while(t--)
 	{
 		long long a, b;
 		scanf("%lld%lld", &a, &b);
 		long long k=a|(b-a);
 		if((b>=a)&&k==a)
 			printf("Possible\n");
 		else 
 			printf("Impossible\n");
	}
	return 0;
 }
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值