A 空间
思路:
一个8位二进制整数占1个字节(1B)
一个32位二进制整数占4个字节(4B)
1MB=1024KB
1KB=1024B
ans=256*
1024*
1024/
4
答案:
67108864
B 卡片
思路:
设一个大小为10的int数组N[10],下标代表卡片的数字,每个元素赋值为2021。
写一个bool函数,fun(int n) 判断n的每位数字的卡片数量>=0
注:不要忘了要减一
答案:
3181
#include<iostream>
using namespace std;
int N[10]={0};
bool fun(int n)
{
while(n>0)
{
N[n%10]-=1;
if(N[n%10]<0)
return false;
n/=10;
}
return true;
}
int main()
{
for(int i=0;i<10;i++)
{
N[i]=2021;
}
int i;
for(i=1;fun(i);i++);
cout << i-1;
return 0;
}
C 直线
思路:
利用两点式得直线方程一般式
(y1-y2)x+(x2-x1)y+x1y2-x2y1=0
A=y1-y2
;
B=x2-x1
;
C=x1y2-x2y1
;
遍历所有可能出现的直线(除了竖,横)
求出他们三个的最大公约数并将A,B,C化为最简
利用map映射排重
答案:
40257
/*
map内部存储机制是红黑树为基础,插入节点时
必须按照大小比对后在一个合适的位置执行插入动作
所以必须要有 "<"
*/
#include<iostream>
#include<map>
using namespace std;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
class ABC
{
public:
int A;
int B;
int C;
ABC()
{
A=0;B=0;C=0;
}
ABC(int a,int b,int c)
{
int bei;
if(c==0)
bei=gcd(a,b);
else bei=gcd(gcd(a,b),c);
A=a/bei;
B=b/bei;
C=c/bei;
}
bool operator ==(ABC a1)//想让他判断是否已经存在 ,但是好像不需要这个
{
if(a1.A==A&&a1.B==B&&a1.C==C)
{
return true;
}
else return false;
}
};
bool operator < (ABC a,ABC b)
{
if(a.A<b.A)
return true;
else if(a.A==b.A&&a.B<b.B)
return true;
else if(a.A==b.A&&a.B==b.B&&a.C<b.C)
return true;
return false;
}
map<ABC,int>mp;
int main()
{
int x1,y1,x2,y2;
int A,B,C;
int ans=0;
for(y2=1;y2<21;y2++)
{
for(x2=0;x2<20;x2++)
{
for(y1=0;y1<=y2;y1++)
{
for(x1=0;x1<20;x1++)
{
if(y1-y2==0)
continue;
else if(x2-x1==0)
continue;
A=y1-y2;
B=x2-x1;
C=y2*x1-x2*y1;
ABC a(A,B,C);
if(mp[a]!=1)
{
mp[a]=1;
ans++;
}
}
}
}
}
cout << ans+21+20;
return 0;
}
D 货物摆放
思路:
求出2021041820210418的所有因子
三重循环遍历即可
注:long long 最大可19位
答案:
2430
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
long long int n=2021041820210418;
long long int N[130];//因子
//int i_ans=0;
int ans=0;
int j=0;
for(long long int i=1;i<=sqrt(n);i++)
{
if(n%i==0)
{
//i_ans+=2;
N[j++]=i;
N[j++]=n/i;
}
}
//cout << i_ans; i_ans=128 即有128个因子
for(int i=0;i<128;i++)
{
for(int j=0;j<128;j++)
{
for(int k=0;k<128;k++)
{
if(N[i]*N[j]*N[k]==2021041820210418)
ans++;
}
}
}
cout << ans;
}
E 路径
思路:
这很明显是一道dp题
要求从1到2021的最短距离,就是从1开始,依次求出到2,到3,到4……到2021的最短距离。
例子:
若要求1-4的最短距离,就求出min(1->
2)+lcm(2,4),min(1->
3)+lcm(3,4),lcm(1,4) 的最小值
若要求1-24的最短距离(24-21=3所以从3开始),就要求出min(1->
3)+lcm(3,24),min(1->
4)+lcm(4,24)……,min(1->
23)+lcm(23,24) 的最短距离
.
可能有人会疑惑1->
24的最短距离?不是1只能到22吗?答:当你算出1->
24的最短距离后,dp[24]代表的就是1->
24的最短距离。dp[23]就是min(1->
23)。
参考以下解析加强理解:
答案:
10266837
#include <iostream>
using namespace std;
int dp[2022];
int gcd(int a, int b) //求出最大公约数
{
return b ? gcd(b, a % b) : a;
}
int lcm(int a, int b) //最小公倍数
{
return a * b / gcd(a, b);
}
void fun(int n)
{
int i;
if (n < 22)
i = 1;
else
i = n - 21;
int min = dp[i] + lcm(i, n);
for (++i; i < n; i++)
{
int temp = dp[i] + lcm(i, n);
min = temp > min ? min : temp;
}
dp[n] = min;
return;
}
int main()
{
dp[1] = 0;
for (int i = 2; i <= 2021; i++)
{
fun(i);
}
cout << dp[2021];
}
F 时间显示
【样例输入1】
46800999
【样例输出1】
13:00:00
【样例输入2】
1618708103123
【样例输出2】
01:08:23
【评测用例规模与约定】
对于所有评测用例,给定的时间为不超过 1018 的正整数。
思路:
1秒等于1000毫秒
将毫秒位直接咔嚓了变成秒,然后进行天数取余,小时取余,分钟数取余
long long 最大1019
答案:
//一天 86400 秒
//一小时 3600 秒
//一分钟 60 秒
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
long long int n;
int h,m,s;
cin >> n;
n/=1000;//咔嚓毫秒
n=n%86400;//天数取余
h=n/3600;
n=n%3600;//小时取余
m=n/60;
n=n%60;//分钟数取余
s=n;
printf("%02d:%02d:%02d",h,m,s);
return 0;
}
G 砝码称重
【样例输入】
3
1 4 6
【样例输出】
10
【样例说明】
能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。
1 = 1;
2 = 6 − 4 (天平一边放 6,另一边放 4);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
9 = 4 + 6 − 1;
10 = 4 +6;
11 = 1 + 4 + 6。
【评测用例规模与约定】
对于 50% 的评测用例,1 ≤ N ≤ 15。
对于所有评测用例,1 ≤ N ≤ 100,N 个砝码总重不超过 100000。
思路1(考场思路):
- 类似于dp
- 设一个vector容器(与int动态数组同理)
- map查重
- 每次拿出一个砝码,与vector容器前面存的依次做加减法,若新得到的数在vector中没有出现,那就放到vector容器中(每次放入vector中都要验重,包括砝码)
批注:显然会超时,如果有更好的方法欢迎在评论区留言
思路2(学习别人的):
讲解地址:https://www.bilibili.com/video/BV1fv411L78t?p=1
跟着y总学,用闫氏dp分析法
答案1(原始):下面有 答案2
#include<iostream>
#include<vector>
#include<map>
using namespace std;
int ABS(int n)
{
return n>0?n:(-n);
}
int main()
{
vector<int>v;
map<int,int>mp;
mp[0]=1;
int N;
cin >> N;
long long int ans=0;
int j=0;
for(int i=0;i<N;i++)
{
int temp;
cin >> temp;
if(mp[temp]==0)
{
mp[temp]=1;
v.push_back(temp);
ans++;
j=ans;
}
else j=ans+1;
for(int i=0;i<j-1;i++)
{
if(mp[ABS(temp-v[i])]==0)
{
ans++;
v.push_back(ABS(temp-v[i]));
mp[ABS(temp-v[i])]=1;
}
if(mp[temp+v[i]]==0)
{
ans++;
v.push_back(temp+v[i]);
mp[temp+v[i]]=1;
}
}
}
/* for(int i=0;i<ans;i++)
{
cout << v[i]<< " ";
}
cout << endl;
*/
cout << ans;
return 0;
}
答案2:
#include<iostream>
#include<algorithm>
using namespace std;
#define N 110
#define M 200010
int a[N];
bool dp[N][M];
int main()
{
int n;
int m=0;//记录砝码总重
cin >> n;
for(int i=1;i<=n;i++)
{
cin >> a[i];
m+=a[i];
}
dp[0][0]=true;
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
dp[i][j]=dp[i-1][j]||dp[i-1][j+a[i]]||dp[i-1][abs(j-a[i])];//三个中有任意1个为true就可以
int ans=0;
for(int j=1;j<=m;j++)
{
if(dp[n][j])
ans++;
}
cout << ans;
return 0;
}
附1:得到100个随机数
#include<stdio.h>
#include<stdlib.h>
#include<time.h>//这里
#define random1(x,y) (rand()%(y-x+1)+x)
int main()
{
srand( (unsigned)time( NULL ) );//这里
int i;
for(i=0;i<100;i++)
{
printf("%d\n",random1(1,100000));//1~100000之间随机数
}
return 0;
}
H 杨辉三角
【样例输入】
6
【样例输出】
13
【评测用例规模与约定】
对于 20% 的评测用例,1 ≤ N ≤ 10;
对于所有评测用例,1 ≤ N ≤ 1000000000。
思路:
- 每行的每个元素除了第一个和最后一个都是自己上面的左右两个相加得到的结果
- 利用滚动数组(节省空间),来得到杨辉三角的每个数。
批注:方法过于暴力,如果有更好的方法欢迎在评论区留言
答案:
#include<iostream>
using namespace std;
long long int ans=1;
int *N;
int main()
{
N=new int[1];
N[0]=1;
long long int n ;
cin >> n;
if(n==1)
cout << 1;
else
{
for(int i=2;;i++)
{
int *P=new int[i];
int tool=0;//判断有没有找到这个数,用来结束循环
for(int j=0;j<i;j++)
{
if(j==0||j==i-1)
{
P[j]=1;
}
else P[j]=N[j-1]+N[j];
if(P[j]==n)
{
ans++;
tool=1;
break;
}
else ans++;
}
if(tool)
break;
delete(N);
N=P;
}
cout << ans;
}
return 0;
}
I 双向排序
【样例输入】
3 3
0 3
1 2
0 2
【样例输出】
3 1 2
【样例说明】
原数列为 (1, 2, 3)。
第 1 步后为 (3, 2, 1)。
第 2 步后为 (3, 1, 2)。
第 3 步后为 (3, 1, 2)。与第 2 步操作后相同,因为前两个数已经是降序了。
【评测用例规模与约定】
对于 30% 的评测用例,n, m ≤ 1000;
对于 60% 的评测用例,n, m ≤ 5000;
对于所有评测用例,1 ≤ n, m ≤ 100000,0 ≤ ai ≤ 1,1 ≤ bi ≤ n。
思路:
傻乎乎的用快排
批注:最多只能过前60%的样例,如果有更好的方法欢迎在评论区留言
答案:
#include<iostream>
using namespace std;
int *N;
void Quick1(int i,int j)//升
{
if(i>=j)
return;
int mid=(i+j)/2;
int s=N[mid];
N[mid]=N[i];
int n=i,m=j;
while(n<m)
{
while(n<m)
{
if(N[m]>s)
{
m--;
}
else
{
N[n++]=N[m];
break;
}
}
while(n<m)
{
if(N[n]<s)
{
n++;
}
else
{
N[m--]=N[n];
break;
}
}
}
N[m]=s;
Quick1(i,m-1);
Quick1(m+1,j);
}
void Quick2(int i,int j)//降
{
if(i>=j)
return;
int mid=(i+j)/2;
int s=N[mid];
N[mid]=N[i];
int n=i,m=j;
while(n<m)
{
while(n<m)
{
if(N[m]<s)
{
m--;
}
else
{
N[n++]=N[m];
break;
}
}
while(n<m)
{
if(N[n]>s)
{
n++;
}
else
{
N[m--]=N[n];
break;
}
}
}
N[m]=s;
Quick2(i,m-1);
Quick2(m+1,j);
}
int main()
{
int n,m;//n个数 m次操作
cin >> n>> m;
N=new int[n+1];
for(int i=1;i<=n;i++)
{
N[i]=i;
}
while(m--)
{
int pi,qi;
cin >> pi >> qi;
if(pi==0)
{
Quick2(1,qi);
}
else Quick1(qi,n);
}
for(int i=1;i<=n;i++)
{
cout << N[i] << " ";
}
return 0;
}
J 括号序列(菜批博主不会)
【样例输入】
((()
【样例输出】
5
【评测用例规模与约定】
对于 40% 的评测用例,|s| ≤ 200。
对于所有评测用例,1 ≤ |s| ≤ 5000。
批注:菜批博主正在努力