1、P8682 [蓝桥杯 2019 省 B] 等差数列
一个找最大公约数的题,复习一下找最大公约数
int gcd(int a,int b){
return b?gcd(a,a%b):a);
}
b==0时候返回a,否则递归
思路:首先对数组进行排序,然后中出两两元素之间差的最大公约数,因为两两元素之间的差一定是公差的整数倍,要想数组最短就要公差最大。找出最大公约数之后,如果最大公约数等于0,则数组长度等于n,否则等于(最大数-最小数)/最大公约数+1
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
long long a[N];
int n;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
sort(a+1,a+1+n);
int pp=a[2]-a[1];
for(int i=3;i<=n;i++)
pp=gcd(pp,a[i]-a[i-1]);
long long count=0;
if(pp==0) count=n;
else count=(a[n]-a[1])/pp+1;
cout<<count<<endl;
return 0;
}
2、P8651 [蓝桥杯 2017 省 B] 日期问题
这个题目比较繁琐,
小明正在整理一批历史文献。这些历史文献中出现了很多日期。
小明知道这些日期都在1960年1月1日至2059年12月31日。
令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。
更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。
比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。
给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?
输入格式
一个日期,格式是”AA/BB/CC”。
即每个’/’隔开的部分由两个 0-9 之间的数字(不一定相同)组成。
输出格式
输出若干个不相同的日期,每个日期一行,格式是”yyyy-MM-dd”。
多个日期按从早到晚排列。
思路:首先对每一种情况需要判断年月日日否符合规范,这里需要复习一下判断闰年的表示方式
//判断闰年
if(x%4==0&&x%100!=0||x%400==0)
之后就是对每一种情况进行检查,比较讨厌的一点是要按照从小到大的顺序进行排列,所以选择用结构体进行排列,之后对于相同的情况进行特判。y总采用的方式是列举日期。
#include<iostream>
#include<algorithm>
const int N=10;
using namespace std;
struct date{
int year;
int month;
int day;
}d[N];
bool cmp(date a,date b){
if(a.year !=b.year ) return a.year <b.year ;
else if(a.month !=b.month ) return a.month <b.month ;
else if(a.day !=b.day ) return a.day <b.day ;
}
int check(int x,int y,int z){
if(y<1||y>12) return 0;
if(y==1||y==3||y==5||y==7||y==8
||y==10||y==12){
if(z<1||z>31) return 0;
}
if(y==4||y==6||y==9||y==11){
if(z<1||z>30) return 0;
}
if(y==2){
if(x%4==0&&x%100!=0||x%400==0){
if(z<1||z>29) return 0;
}
else if(z<1||z>28) return 0;
}
return 1;
}
int main(){
int a,b,c,i=1;
scanf("%02d/%02d/%02d",&a,&b,&c);
if(a>=60){
int t=a+1900;
if(check(t,b,c))
{
d[i].year=t;
d[i].month=b;
d[i].day =c;
i++;
}
//printf("%d-%02d-%02d\n",t,b,c);
}
else if(a<=59){
int t=a+2000;
if(check(t,b,c))
//printf("%d-%02d-%02d\n",t,b,c);
{
d[i].year=t;
d[i].month=b;
d[i].day =c;
i++;
}
}
if(c>=60){
int t=c+1900;
if(check(t,a,b))
//printf("%d-%02d-%02d\n",t,a,b);
{
d[i].year=t;
d[i].month=a;
d[i].day =b;
i++;
}
if(check(t,b,a))
//printf("%d-%02d-%02d\n",t,b,a);
{
d[i].year=t;
d[i].month=b;
d[i].day =a;
i++;
}
}
else if(c<=59){
int t=c+2000;
if(check(t,a,b))
//printf("%d-%02d-%02d\n",t,a,b);
{
d[i].year=t;
d[i].month=a;
d[i].day =b;
i++;
}
if(check(t,b,a))
// printf("%d-%02d-%02d\n",t,b,a);
{
d[i].year=t;
d[i].month=b;
d[i].day =a;
i++;
}
}
sort(d+1,d+1+i-1,cmp);
for(int j=1;j<i;j++){
bool flag=1;
if(d[j].year ==d[j-1].year &&d[j].month ==d[j-1].month &&d[j].day ==d[j-1].day ) flag=0;
if(flag==1)
printf("%d-%02d-%02d\n",d[j].year ,d[j].month ,d[j].day );
}
return 0;
}
3、P8635 [蓝桥杯 2016 省 AB] 四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多 44 个正整数的平方和。
如果把 00 包括进去,就正好可以表示为 44 个数的平方和。
比如:
5=02+02+12+225=02+02+12+22。
7=12+12+12+227=12+12+12+22。
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对 44 个数排序使得 0≤a≤b≤c≤d。
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法。
思路:暴力搜索
#include<iostream>
#include<cmath>
using namespace std;
int n,a,b,c,d;
int check(int x,int y,int z,int s)
{
return x*x+y*y+z*z+s*s;
}
int main(){
cin>>n;
for(int i=0;;i++){
if(check(i,i,i,i)>n) break;
for(int j=i;;j++){
if(check(j,j,j,j)>n) break;
for(int k=j;;k++){
if(check(k,k,k,k)>n) break;
int t=sqrt(n-i*i-j*j-k*k);
if(check(i,j,k,t)==n)
{
cout<<i<<" "<<j<<" "<<k<<" "<<t<<endl;
return 0;
}
}
}
}
return 0;
}
4、P8754 [蓝桥杯 2021 省 AB2] 完全平方数
一个整数 a是一个完全平方数,是指它是某一个整数的平方,即存在一个整数 b,使得 a=b^2。
给定一个正整数 n,请找到最小的正整数 x,使得它们的乘积是一个完全平方数。
输入格式
输入一行包含一个正整数 n。
输出格式
输出找到的最小的正整数 x。
直接暴力会超时,这里有一个小知识点:一个完全平方数一定可以分成若干个质因子相乘,并且每个质因子的次数一定是偶数次(因为完全平方嘛)所以这个题目如果n*x是一个完全平方,那么县看n里面质因子次数,如果是偶数次的就跳过,如果是奇数次的就需要再乘上一个变成偶数次,也就是说x等于奇数次的质因子相乘
这里有一个求质因子的板子(找到一个好东西acwing里面y总有总结很多的基本算法模版,比赛之前要好好看一下)
#include<iostream>
using namespace std;
long long n,x=1;
int main(){
scanf("%lld",&n);
for(long long i=2;i*i<=n;i++){
if(n%i==0){
int t=0;
while(n%i==0){
n=n/i;
t++;
}
if(t%2==1) x=x*i;
}
}
if(n>1) x=x*n; //最后还要看一下是不是除尽了
printf("%lld\n",x);
return 0;
}
5、P8707 [蓝桥杯 2020 省 AB1] 走方格
在平面上有一些二维的点阵。
这些点的编号就像二维数组的编号一样,从上到下依次为第 11 至第 n� 行,从左到右依次为第 11 至第 m 列,每一个点可以用行号和列号来表示。
现在有个人站在第 11 行第 11 列,要走到第 n� 行第 m� 列。
只能向右或者向下走。
注意,如果行号和列数都是偶数,不能走入这一格中。
问有多少种方案。
思路:动态规划,当i==n&&j==m时 f=1 当是偶数时 f=0 其余情况f[i][j]=f[i-1][j]+f[i][j-1]
#include<iostream>
using namespace std;
long long n,m;
long long f[189][189];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i==1&&j==1)
f[i][j]=1;
else if(i%2==1||j%2==1)
f[i][j]=f[i-1][j]+f[i][j-1];
}
}
cout<<f[n][m]<<endl;
return 0;
}