01题 X进制减法 2022 省赛E题
题目描述
Code
using namespace std;
const int M=1e5,mod=1e9+7;
typedef long long ll;
int n; //最高进制n
int A,B;//A B两数位数
int Ma,Mb;//A B两数十进制数
int a[M],b[M],w[M];
int x;//最高位数
int mul=0;
int main()
{
cin>>n;
cin>>A;
for(int i=A-1;i>=0;i--){
cin>>a[i];
}
cin>>B;
for(int i=B-1;i>=0;i--){
cin>>b[i];
}
//数组中低位存储进制数低位
if(A!=B&&A<n&&B<n)
x=(A>=B)?A:B;
else
x=A;
//保存每位的j进制 最低位为二进制
w[0]=2;
int wgt=1; //记录权重
for(int i=1;i<x;i++){
a[i]>b[i]?w[i]=a[i]+1:w[i]=b[i]+1;
}
for(int i=0;i<x;i++){
mul+=(a[i]-b[i])*wgt;
wgt*=w[i];
}
cout<<mul;
return 0;
}
注意事项
- 理解进制的概念,本题易错在计算每位的权重上,十进制381=3×10×10+8×10+1×1,而在本题的X进制中381(X)=3×9×2+8×2+1×1=71(10),切勿理解为381(X)=3×90+8×20+1×1=431(10)。
- 贪心算法:数的每位都选用对A和B来说合理的进制最小但不低于2的进制,A-B的值最小。就比如第i位,A的数为3,B的数为4,对A来说进制最小为4,对B来说进制最小为5,那么对A和B来说该位合理的进制最小为5。每位的进制得出来后,再算出每位的权值。
02题 日期位数之和 2023 模拟赛第三期C题
问题描述
对于一个日期,我们可以计算出年份的各个数位上的数字之和,也可以分别计算月和日的各位数字之和。请问从 1900 年 1 月 1 日至 9999 年 12 月 31 日,总共有多少天,年份的数位数字之和等于月的数位数字之和加日的数位数字之和。 例如,2022年11月13日满足要求,因为 2+0+2+2=(1+1)+(1+3) 。 请提交满足条件的日期的总数量。
答案:70910
模板总结
- 计算日期之间的天数(判断闰年)
int month[13][2]={{0,0},{31,31},{28,29},{31,31},{30,30},{31,31},{30,30},{31,31},{31,31},{30,30},{31,31},{30,30},{31,31}};
bool isLeap(int year)
{
return (year%4==0 && year%100!=0) || (year%400==0);
}
int main(){
int time1,y1,m1,d1;
int time2,y2,m2,d2;
int ans=0;
scanf("%d%d",&time1,&time2);
if(time1>time2){
int tmp=time1;
time1=time2;
time2=tmp;
}
y1=time1/10000,m1=time1%10000/100,d1=time1%100;
y2=time2/10000,m2=time2%10000/100,d2=time2%100;
while(y1<y2 || m1<m2 || d1<d2) {
d1++;
if(d1==month[m1][isLeap(y1)]+1) { //满月天数
m1++;
d1=1;
}
if(m1==13) {
y1++;
m1=1;
}
ans++;
}
cout<<ans;
return 0;
}
- 分解位数(较小位数的数字),在数字位数较大的情况下应转化为字符串处理
int tmp1=y1,tmp2=m1,tmp3=d1;
int sum1=0,sum2=0;
while(tmp1){
sum1+=tmp1%10;
tmp1/=10;
}
for(int i=0;i<2;i++){
sum2+=tmp2%10+tmp3%10;
tmp2/=10;
tmp3/=10;
}
Code
#include<bits/stdc++.h>
using namespace std;
int month[13][2]={{0,0},{31,31},{28,29},{31,31},{30,30},{31,31},{30,30},{31,31},{31,31},{30,30},{31,31},{30,30},{31,31}};
bool isLeap(int year)
{
return (year%4==0 && year%100!=0) || (year%400==0);
}
int main(){
int time1,y1,m1,d1;
int time2,y2,m2,d2;
int ans=0;
scanf("%d%d",&time1,&time2);
if(time1>time2){
int tmp=time1;
time1=time2;
time2=tmp;
}
y1=time1/10000,m1=time1%10000/100,d1=time1%100;
y2=time2/10000,m2=time2%10000/100,d2=time2%100;
while(y1<y2 || m1<m2 || d1<d2) {
d1++;
if(d1==month[m1][isLeap(y1)]+1) { //满月天数
m1++;
d1=1;
}
if(m1==13) {
y1++;
m1=1;
}
int tmp1=y1,tmp2=m1,tmp3=d1;
int sum1=0,sum2=0;
while(tmp1){
sum1+=tmp1%10;
tmp1/=10;
}
for(int i=0;i<2;i++){
sum2+=tmp2%10+tmp3%10;
tmp2/=10;
tmp3/=10;
}
if(sum1==sum2){
ans++;
}
}
cout<<ans;
return 0;
}
03题 信号塔检测 2023 模拟赛第三期G题
问题描述
小蓝负责一块区域的信号塔安装,整块区域是一个长方形区域,建立坐标轴后,西南角坐标为 (0, 0), 东南角坐标为 (W, 0), 西北角坐标为 (0, H), 东北角坐标为 (W, H)。其中 W, H 都是整数。 他在 n 个位置设置了信号塔,每个信号塔可以覆盖以自己为圆心,半径为 R 的圆形(包括边缘)。 为了对信号覆盖的情况进行检查,小蓝打算在区域内的所有横纵坐标为整数的点进行测试,检查信号状态。其中横坐标范围为 0 到 W,纵坐标范围为 0 到 H,总共测试 (W+1) * (H+1) 个点。 给定信号塔的位置,请问这 (W+1)*(H+1) 个点中有多少个点被信号覆盖。
输入格式 输入第一行包含四个整数 W, H, n, R,相邻整数之间使用一个空格分隔。 接下来 n 行,每行包含两个整数 x, y,表示一个信号塔的坐标。信号塔可能重合,表示两个信号发射器装在了同一个位置。
输出格式 输出一行包含一个整数,表示答案。
样例输入
10 10 2 5
0 0
7 0
样例输出
57
评测用例规模与约定 对于所有评测用例,1 <= W, H <= 100,1 <= n <= 100, 1 <= R <= 100, 0 <= x <= W, 0 <= y <= H。
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int W,H,n,R,ans,x,y;
bool vis[maxn][maxn];
void judge()
{
for(int i=0;i<=W;i++){
for(int j=0;j<=H;j++){
if(!vis[i][j] && (x-i)*(x-i)+(y-j)*(y-j)<=R*R){
vis[i][j]=true;
ans++;
}
}
}
}
int main()
{
cin>>W>>H>>n>>R;
for(int i=0;i<n;i++){
cin>>x>>y;
judge();
}
cout<<ans;
return 0;
}
注意事项
- 本题只需要统计最后的个数,不需要将数据记录下来
- 注意记忆只需访问未被信号覆盖的点,减少搜索量
04题 网格压缩 2023 成都大学contest 5 A题
问题描述:
给出H×W的图,如果这个图上一行或一列没有#的话将这一行或这一列删除,输出处理完后的图。1<=H,W<=100
输入描述:
H W
a1,1...a1W
.
.
aH,1...aH,W
输出描述:
打印出处理完后的图
样例输入
4 4
##.#
....
##.#
.#.#
样例输出
###
###
.##
Code
#include <iostream>
#include <vector>
using namespace std;
int main() {
int H, W;
cin >> H >> W;
vector<vector<char> > board(H, vector<char>(W)); // 储存图
vector<bool> row(H, false); // 行是否有 #
vector<bool> col(W, false); // 列是否有 #
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
cin >> board[i][j];
if (board[i][j] == '#') { // 如果这个位置有 #
row[i] = true;
col[j] = true;
}
}
}
for (int i = 0; i < H; i++) {
if (row[i]) { // 如果这一行有 #
for (int j = 0; j < W; j++) {
if(col[j]) { // 如果这一列有 #
cout << board[i][j];
}
}
cout << endl;
}
}
return 0;
}
05题 跳出实验室 2023 成都大学contest5 B题
问题描述
该情景可抽象在线性坐标系中,小华在跳出实验室时遇到了一扇门需要打开。
这扇门有N个开关,第i个开关在坐标xi处,一开始小华在坐标0处。
当打开至少K个开关时,这扇门就会打开。
如果Lin的移动速度为1,打开开关忽略不计,问小华至少要花费多少时间才能使这扇门打开。
样例输入
N K
x1 x2 ... xn
样例输出
40
Code
06题 轻重搭配
问题描述
某一天,zxl 和 rys 一起去动物园参观,他们来到了售票处正好有一个符合他们体重的活动正在进行。 一共有 n 个同学去动物园参观,原本每人都需要买一张门票,但售票处推出了一个优惠活动,一个体重为 x 的人可以和体重至少为 2·x 配对,这样两人只需买一张票。现在给出了 n 个人的体重,请你计算他们最少需要买几张门票?
类型
二分 贪心
Code
#include <bits/stdc++.h>
using namespace std;
int a[500005];
int main() {
int n;
cin>>n;
for (int i = 0; i < n; i++) {
cin>>a[i];
}
sort(a, a + n);
int ans = n, pos = n / 2;
for (int i = 0; i < n / 2; i++) {
while (pos < n && a[pos] < a[i] * 2) pos++;
if (pos == n) break;
ans--;
pos++;
}
cout<<ans;
return 0;
}
07题 月饼 PAT B1020
类型
贪心 排序 结构体
题目描述
样例输入
Code
#include<bits/stdc++.h>
using namespace std;
struct mooncake {
double store;
double sell;
double price;
}cake[1010];
bool cmp(mooncake a,mooncake b){
return a.price>b.price;
}
int main()
{
int n;
double D;
cin>>n>>D;
for(int i=0;i<n;i++){
cin>>cake[i].store;
}
for(int i=0;i<n;i++){
cin>>cake[i].sell;
cake[i].price=cake[i].sell/cake[i].store;
}
sort(cake,cake+n,cmp);
double ans=0;
for(int i=0;i<n;i++){
if(cake[i].store<=D){
D-=cake[i].store;
ans+=cake[i].sell;
}else{
ans+=cake[i].price*D;
break;
}
}
printf("%.2f\n",ans);
return 0;
}
08题 不交区间
类型
区间贪心
题目描述
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=110;
struct Inteval {
int x,y;//区间左右端点
} I[maxn];
bool cmp(Inteval a,Inteval b) {
if(a.x!=b.x) return a.x>b.x;
else return a.y<b.y;
}
int main() {
int n;
while(cin>>n,n!=0) {
for(int i=0; i<n; i++) {
cin>>I[i].x>>I[i].y;
}
sort(I,I+n,cmp);
int ans=1,lastX=I[0].x;
for(int i=1; i<n; i++) {
if(I[i].y<=lastX) {//如果该区间右端点在lastX左边
lastX=I[i].x;
ans++;
}
}
cout<<ans<<endl;
}
return 0;
}
09题 01背包问题
类型
贪心 DFS
题目描述
样例输入
5 8
3 5 1 2 2
4 5 2 1 3
样例输出
10
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=30;
int n,V,maxValue=0; //物品件数,背包容量,最大价值
int w[maxn],c[maxn]; //每件物品重量,每件物品价值
//sumW和sumC为当前总重量和总价值
void DFS(int index, int sumW, int sumC)
{
if(index==n){
if(sumW<=V&&sumC>maxValue){
maxValue=sumC;
}
return;
}
//选择
DFS(index+1,sumW,sumC); //不选第index件物品
DFS(index+1,sumW+w[index],sumC+c[index]); //选第index件物品
}
int main()
{
cin>>n>>V;
for(int i=0;i<n;i++){
cin>>w[i];
}
for(int i=0;i<n;i++){
cin>>c[i];
}
DFS(0,0,0);
cout<<maxValue;
return 0;
}
优化
由于每件物品都有两种选择,因此上述代码时间复杂度为O(2^n)。在上述代码中,总是把n件物品全部选择后才去更新最大价值,事实上忽略了背包容量不超过V这个特点,也就是说可以把对sumV的判断加入“岔道口”中,只有当sumV<=V时才进入岔道。这种通过题目条件来减少DFS计算量的方法称为“剪枝”。
void DFS(int index, int sumW, int sumC)
{
if(index==n){
return;
}
DFS(index+1, sumW, sumC);
if(sumW+w[index]<=V){
if(sumC+c[index]>maxValue){
maxValue=sumC+c[index];
}
DFS(index+1,sumW+w[index],sumC+c[index]);
}
}
10题 数塔问题
题目描述
样例输入
5
5
8 3
12 7 16
4 10 11 6
9 5 3 9 4
样例输出
44
类型
动态规划:
一个问题可以分解为若干个子问题,且这些子问题会重复出现,称这个问题拥有重叠子问题。
一个问题的最优解,可以由其子问题的最优解有效构造出来,称为这个问题拥有最优子结构。
一个问题拥有重叠子问题和最优子结构才能用动态规划解决问题
- 定义状态
- 定义状态转移方程
- 定义边界
- 求解问题
Code
递推实现 自底向上
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000;
int f[maxn][maxn], dp[maxn][maxn];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
cin>>f[i][j];
}
}
//边界
for(int i=1;i<=n;i++){
dp[n][i]=f[n][i];
}
for(int i=n-1;i>=1;i--){
for(int j=1;j<=i;j++){
//状态转移方程
dp[i][j]=max(dp[i+1][j], dp[i+1][j+1])+f[i][j];
}
}
cout<<dp[1][1]<<endl;
return 0;
}
递归实现 自顶向下
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000;
int f[maxn][maxn], dp[maxn][maxn];
int n;
int Fn(int x,int y)
{
//边界
if(x==n) return f[x][y];
if(dp[x][y]!=-1) return dp[x][y];
else{
dp[x][y]=max(Fn(x+1,y), Fn(x+1,y+1) )+f[x][y];//状态转移方程
return dp[x][y];
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
cin>>f[i][j];
}
}
//初始化 dp数组
memset(dp, -1, sizeof(dp));
//边界
for(int i=1;i<=n;i++){
dp[n][i]=f[n][i];
}
int ans=Fn(1,1);
cout<<ans<<endl;
return 0;
}
11题 最大连续子序列和
题目描述
样例输入
6
-2 11 -4 13 -5 -2
样例输出
20
Code
递归实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=10010;
int f[maxn], dp[maxn];
int Fn(int x)
{
if(x==0) return f[0];
if(dp[x]!=-1) return dp[x];
else{
dp[x]=max(f[x], Fn(x-1)+f[x]);//状态转移方程
return dp[x];
}
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>f[i];
}
memset(dp, -1, sizeof(dp));
//边界条件
dp[0]=f[0];
Fn(n);
int k=0;
for(int i=0;i<n;i++){
if(dp[i]>dp[k])
k=i;
}
cout<<dp[k]<<endl;
return 0;
}
12题 最长不下降子序列(LIS)
问题描述
样例输入
8
1 2 3 -9 3 9 0 11
样例输出
6
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=100;
int f[maxn], dp[maxn];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>f[i];
}
int ans=-1;
for(int i=1;i<=n;i++){
dp[i]=1;//边界初始条件
for(int j=1;j<i;j++){
if(f[j]<=f[i] && (dp[j]+1>dp[i])){
dp[i]=dp[j]+1;//状态转移方程
}
}
ans=max(ans,dp[i]);
}
cout<<ans<<endl;
return 0;
}
13题 最长公共子序列(LCS)
题目描述
样例输入
sadstory
adminsorry
样例输出
6
Code
#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 100;
char A[N], B[N];
int dp[N][N];
int main()
{
gets(A+1);
gets(B+1);
int lenA = strlen(A + 1);
int lenB = strlen(B + 1);
//边界
for(int i=0; i<=lenA; i++){
dp[i][0]=0;
}
for(int j=0; j<=lenB; j++){
dp[0][j]=0;
}
//状态转移方程
for(int i=1; i<=lenA; i++){
for(int j=1; j<=lenB; j++){
if(A[i] == B[j]){
dp[i][j]=dp[i-1][j-1]+1;
}else{
dp[i][j]=max(dp[i-1][j], dp[i][j-1]);
}
}
}
cout<<dp[lenA][lenB]<<endl;
return 0;
}
14题 最长回文子串
题目描述
样例输入
PATZJUJZTACCBCC
样例输出
9
Code
#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1010;
char S[N];
//dp[i][j]表示S[i]到S[j]是否为回文串,是为1,否则为0
int dp[N][N];
int main()
{
gets(S);
int len = strlen(S), ans = 1;
//初始化
memset(dp, 0, sizeof(dp));
//边界条件
for(int i = 0; i < len; i++){
dp[i][i] = 1;
if(i < len - 1){
if(S[i] == S[i+1]){
dp[i][i+1]=1;
ans=2;
}
}
}
//状态转移方程
for(int L = 3; L <= len; L++){//枚举子串的长度
for(int i = 0; i + L - 1 < len; i++){//枚举子串的起始端点
int j = i + L - 1;//子串的右端点
if(S[i] == S[j] && dp[i+1][j-1] == 1){
dp[i][j]=1;
ans = L;
}
}
}
cout<<ans<<endl;
return 0;
}
14题 等腰三角形
题目描述
给定 n 个坐标,求其中 3 个坐标能表示一个等腰三角形的组数。
三点共线不算三角形,等边三角形为特殊的等腰三角形。
输入描述 `` 第一行一个整数 n(0≤n≤400)
其后 n 行每行两个整数 xi,yi(−500≤xi,yi≤500),保证没有重复坐标。 ``
输入
4
1 1
-1 1
-1 -1
1 -1
输出
4
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int main() {
int n;
cin>>n;
vector <pii> s(n+1);
for(int i = 1; i <= n; i++)
{
cin>>s[i].first>>s[i].second;
}
if(n <= 2)
{
cout<<0<<endl;
return 0;
}
int cnt=0;
for(int i = 1; i <= n; i++)
{
for(int j = i + 1; j <= n; j++)
{
for(int k = j + 1; k <= n; k++)
{
int x1, y1, x2, y2, x3, y3;
x1 = s[i].first, y1 = s[i].second;
x2 = s[j].first, y2 = s[j].second;
x3 = s[k].first, y3 = s[k].second;
//向量积(x1-x3,y1-y3)×(x2-x3,y2-y3)
int crossProduct = (x1-x3)*(y2-y3) - (x2-x3)*(y1-y3);
if(crossProduct == 0) // 三点共线
continue;
int a = (pow(x1-x2, 2) + pow(y1-y2,2));
int b = (pow(x1-x3, 2) + pow(y1-y3,2));
int c = (pow(x2-x3, 2) + pow(y2-y3,2));
if(a==b || a==c || b==c) // 是等腰三角形
cnt++;
}
}
}
cout<<cnt<<endl;
}
15题 块
题目描述
Code
BFS实现:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100;
struct node{
int x,y;
}Node;
int n=7,m=7;
bool inq[maxn][maxn]={false};
int matrix[maxn][maxn]={{0,1,1,1,0,0,1},{0,0,1,0,0,0,0},{0,0,0,0,1,0,0},{0,0,0,1,1,1,0},{1,1,1,0,1,0,0},{1,1,1,1,0,0,0}};
//增量数组
int X[4]={0,0,-1,1};
int Y[4]={1,-1,0,0};
//边界条件
bool judge(int x,int y){
if(x>=n || x<0 ||y>=m || y<0){
return false;
}
if(matrix[x][y]==0 || inq[x][y]==true){
return false;
}
return true;
}
//BFS访问(x,y)所在的块,将块中所有"1"设置为true
void BFS(int x,int y){
queue<node> Q;
Node.x=x;
Node.y=y;
Q.push(Node);
inq[x][y]=true;
while(!Q.empty()){
node top=Q.front();
Q.pop();
for(int i=0;i<4;i++){
int newX=top.x+X[i];
int newY=top.y+Y[i];
if(judge(newX,newY)){
Node.x=newX;
Node.y=newY;
Q.push(Node);
inq[newX][newY]=true;
}
}
}
}
int main(){
int ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(matrix[i][j]==1 && inq[i][j]==false){
ans++;
BFS(i,j);
}
}
}
cout<<ans<<endl;
return 0;
}
16题 华强劈瓜
问题描述
华强在一个铺着方形地砖的房间中,每块地砖上都放的一个有西瓜。他站在一块放有西瓜的瓷砖上,并且可以上下左右移动到其它瓷砖上,但是前提是瓷砖上得有西瓜,毕竟华强是个爱劈西瓜的人。
请你写一个程序来计算华强能在这个房间里面劈到多少个西瓜。
输入描述
第一行两个整数 n m 代表这个房间里面的瓷砖有n行m列 n和m不超过20
接下来n行,每行包含m个字符,每个字符代表该地砖上是否有瓜,状态如下所示:
'.'有瓜
'#'无瓜
'@'华强的初始位置(只出现一次)
样例输入
9 6
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
样例输出
45
Code
DFS实现:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int dx = 0, dy = 0;
int n, m, res = 1;
char arr[25][25];
int X[4] = {0, 0, 1,-1};
int Y[4] = {1,-1, 0, 0};
struct node {
int x, y;
};
void dfs(int x, int y)
{
queue<node> q;
node start;
start.x = x;
start.y = y;
q.push(start);
while (!q.empty()) {
start = q.front();
q.pop();
for (int i = 0; i < 4; i++) {
int ax = X[i] + start.x;
int ay = Y[i] + start.y;
if (ax >= 0 && ax < n && ay >= 0 && ay < m && arr[ax][ay] == '.') {
arr[ax][ay] = '#';
res++;
dfs(ax, ay);
}
}
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> arr[i][j];
if (arr[i][j] == '@') {
dx = i; dy = j;
}
}
}
dfs(dx, dy);
cout << res << endl;
return 0;
}
BFS实现:
#include<bits/stdc++.h>
using namespace std;
const int maxn=10010;
struct node{
int x,y;
}start;
int n, m;
int dx, dy;
char matrix[maxn][maxn];
int inq[maxn][maxn] = {false};
int X[4]={ 0, 0,-1, 1};
int Y[4]={ 1,-1, 0, 0};
int ans=0;
int cnt=0;
bool judge(int x, int y) {
if(x >= n || x < 0 || y >= m || y < 0) {
return false;
}
if(matrix[x][y] == 0 || inq[x][y] == true) {
return false;
}
if(matrix[x][y] == '#') {
return false;
}
return true;
}
void BFS(int x, int y)
{
queue<node> Q;
start.x = x;
start.y = y;
Q.push(start);
inq[x][y] = true;
while( !Q.empty() ){
node top = Q.front();
Q.pop();
ans++;
inq[start.x][start.y] = true;
for(int i = 0; i < 4; i++){
int newX = top.x + X[i];
int newY = top.y + Y[i];
if(judge(newX, newY)) {
start.x = newX;
start.y = newY;
Q.push(start);
inq[newX][newY] = true;
}
}
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> matrix[i][j];
if (matrix[i][j] == '@') {
dx = i;
dy = j;
matrix[i][j] = '.';
}
}
}
BFS(dx, dy);
cout << ans << endl;
return 0;
}