刷题集合2

描述了一个涉及矩阵操作和动态规划的游戏问题,目标是找到打开冰箱把手的最少切换次数,以及相应的操作步骤。
摘要由CSDN通过智能技术生成

“飞行员兄弟”这个游戏,需要玩家顺利的打开一个拥有16个把手的冰箱。

已知每个把手可以处于以下两种状态之一:打开或关闭。

只有当所有把手都打开时,冰箱才会打开。

把手可以表示为一个4х4的矩阵,您可以改变任何一个位置[i,j]上把手的状态。

但是,这也会使得第i行和第j列上的所有把手的状态也随着改变。

请你求出打开冰箱所需的切换把手的次数最小值是多少。

输入输出格式
输入格式:
输入一共包含四行,每行包含四个把手的初始状态。

符号“+”表示把手处于闭合状态,而符号“-”表示把手处于打开状态。

至少一个手柄的初始状态是关闭的。

输出格式:
第一行输出一个整数N,表示所需的最小切换把手次数。

接下来N行描述切换顺序,每行输入两个整数,代表被切换状态的把手的行号和列号,数字之间用空格隔开。

输入输出样例
输入样例#1: 复制
-+--
----
----
-+--
输出样例#1: 复制
6
1 1
1 3
1 4
4 1
4 3
4 4
说明
1≤i,j≤4


#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int,int> PII;

const int N=5;

char g[N][N],backup[N][N];



int get(int x,int y)
{
    return x*4+y;//返回第x行第y列上的数是多少
}

void turn_one(int x,int y)
{
    if(g[x][y]=='+') g[x][y]='-';
    else g[x][y]='+';
}

void turn_all(int x,int y)
{
    for(int i=0;i<4;i++)
    {
        turn_one(x,i);
        turn_one(i,y);
    }
    turn_one(x,y);

}

int main()
{
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            cin>>g[i][j];

    vector<PII> res;//记录方案所需要的结构

    //枚举所有的方案
    for(int op=0;op<1<<16;op++)
    {
        vector<PII> temp;//temp里面存的是方案
    
        memcpy(backup,g,sizeof g);

        //枚举16个位置,进行操作
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                if(op>>get(i,j)&1) //如果当前位置是1的话--get的作用就是返回二进制数中那一位是第几位,从而判断是否为1
                {
                    temp.push_back({i,j});
                    //按一下开关
                    turn_all(i,j);
                }


        //判断所有灯泡是否全亮
        bool has_closed=false;
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                if(g[i][j]=='+') has_closed=true;

        if(has_closed==false)
        {
            //如果方案为空或者他的操作数大于我们刚存好的新的方案,那么就修改它
            if(res.empty()||res.size()>temp.size()) res=temp;
        }
        //还原回来,供下一个方案操作
        memcpy(g,backup,sizeof g);
    }
  
    cout<<res.size()<<endl;
  
    for(auto op:res) cout<<op.x+1<<" "<<op.y+1<<endl;

    return 0;
}

730. 机器人跳跃问题 

机器人正在玩一个古老的基于 DOS 的游戏。游戏中有 N+1座建筑——从 0到 N
编号,从左到右排列。编号为 0的建筑高度为 0个单位,编号为 i的建筑高度为 H(i)个单位。
起初,机器人在编号为 0 的建筑处。每一步,它跳到下一个(右边)建筑。
假设机器人在第 k个建筑,且它现在的能量值是 E,下一步它将跳到第 k+1个建筑。
如果 H(k+1)>E,那么机器人就失去 H(k+1)−E的能量值,否则它将得到 E−H(k+1) 的能量值。
游戏目标是到达第 N个建筑,在这个过程中能量值不能为负数个单位。
现在的问题是机器人至少以多少能量值开始游戏,才可以保证成功完成游戏?

输入格式

第一行输入整数 N。

第二行是 N 个空格分隔的整数,H(1),H(2),…,H(N)代表建筑物的高度。

输出格式

输出一个整数,表示所需的最少单位的初始能量值上取整后的结果。

数据范围

1≤N,H(i)≤10e5,

输入样例1:
5
3 4 3 2 4
输出样例1:
4
输入样例2:
3
4 4 4
输出样例2:
4
输入样例3:
3
1 6 4
输出样例3:
3

 题解

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100010;
int n;
int h[N];
bool check(int e){
    for(int i=0;i<n;i++){
        e=2*e-h[i];

    if(e>=1e5)return 1;
    if(e<0){
        return 0;
    }}
    return 1;
}

int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&h[i]);
    }
    int l=0,r=1e5;
    while(l<r){
        int mid=l+r>>1;
        if(check(mid)){
            r=mid;
        }
        else{
            l=mid+1;
        }
    }
    cout<<l<<endl;
    
}

1221四平方和定理,又称为拉格朗日定理:

每个正整数都可以表示为至多 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 为联合主键升序排列,最后输出第一个表示法。

输入格式

程序输入为一个正整数0<N<5∗10e6。

输出格式

要求输出 44 个非负整数,按从小到大排序,中间用空格分开。

输入输出样例

输入 #1复制

5

输出 #1复制

0 0 1 2

输入 #2复制

12

输出 #2复制

0 2 2 2

输入 #3复制

773535

输出 #3复制

1 1 267 838

说明/提示

时限 3 秒, 256M。蓝桥杯 2016 年第七届省赛

蓝桥杯 2016 年省赛 A 组 H 题(B 组 H 题)。

二分搜索

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5e6 + 10;
struct Sum{
    int s,c,d;
    bool operator<(const Sum &t)const {
        if(s!=t.s)return s<t.s;
        if(c!=t.c)return c<t.c;
        return d<t.d;
    }
}sum[N];
int m,n;

int main(){
    cin>>n;
    for(int c=0;c*c<=n;c++){
        for(int d=c;d*d+c*c<=n;d++){
            sum[m++]={c*c+d*d,c,d};
        }
    }
    sort(sum,sum+m);
    for(int a=0;a*a<=n;a++){
        for(int b=0;b*b+a*a<=n;b++){
             int t=n-a*a-b*b;
             int l=0;
             int r=m-1;
             while(l<r){
                 int mid=l+r >> 1;
                 if(sum[mid].s>=t){
                     r=mid;
                 }
                 else{
                     l=mid+1;
                 }
                 
             }
             if(sum[l].s==t){
                 printf("%d %d %d %d\n",a,b,sum[l].c,sum[l].d);
                 return 0;
             }
        }
    }
    
    
}

哈希搜索

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<unordered_map>
#define x first
#define y second
using namespace std;
const int N=2500;
typedef pair<int,int>PII;
unordered_map<int,PII>s;
int m,n;

int main(){
    cin>>n;
    for(int c=0;c*c<=n;c++){
        for(int d=c;d*d+c*c<=n;d++){
            int t=c*c+d*d;
            if(s.count(t)==0)s[t]={c,d};
        }
    }
    for(int a=0;a*a<=n;a++){
        for(int b=0;b*b+a*a<=n;b++){
             int t=n-a*a-b*b;
          
             if(s.count(t)!=0){
                 printf("%d %d %d %d\n",a,b,s[t].x,s[t].y);
                 return 0;
             }
        }
    }
    
    
}

模拟哈希

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<unordered_map>
#define x first
#define y second
using namespace std;
const int N= 5e6 + 10;
int r[N*2];
int m,n;

int main(){
    cin>>n;
    memset(r,-1,sizeof r);;
    for(int c=0;c*c<=n;c++){
        for(int d=c;d*d+c*c<=n;d++){
            int t=c*c+d*d;
            if(r[t]==-1)r[t]=c;
        }
    }
    for(int a=0;a*a<=n;a++){
        for(int b=0;b*b+a*a<=n;b++){
             int t=n-a*a-b*b;
               int c=r[t];
             if(r[t]==-1)
             continue;
                 int d=sqrt(t-c*c);
                 printf("%d %d %d %d\n",a,b,c,d);
                 return 0;
             }
        }
    }
    
    

P8647 [蓝桥杯 2017 省 AB] 分巧克力 

题目描述

儿童节那天有 K 位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。

小明一共有 N 块巧克力,其中第 i 块是 Hi​×Wi​ 的方格组成的长方形。

为了公平起见,小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。切出的巧克力需要满足:

  1. 形状是正方形,边长是整数。

  2. 大小相同。

例如一块 6×5的巧克力可以切出 6 块2×2 的巧克力或者 2 块 3×3的巧克力。

当然小朋友们都希望得到的巧克力尽可能大,你能帮小 Hi​ 计算出最大的边长是多少么?

输入格式

第一行包含两个整数 N 和 K。(1≤N,K≤1e5)。

以下 N 行每行包含两个整数Hi​ 和 Wi​。(1≤Hi​,Wi​≤105)。

输入保证每位小朋友至少能获得一块 1×1 的巧克力。

输出格式

输出切出的正方形巧克力最大可能的边长。

输入输出样例

输入 #1复制

2 10  
6 5  
5 6  

输出 #1复制

2

说明/提示

蓝桥杯 2022 省赛 A 组 I 题。

 子矩阵的和

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5;
int n,m;
struct f{
    int a,b;
}f[N];
bool check(int x){
    int tot=0;
    for(int i=0;i<N;i++){
        tot+=(f[i].a/x)*(f[i].b/x);//带括号,否则会影响取整性
    }
    if(tot>=m){
        return 1;
    }
    return 0;
}
int main(){
    cin>>n>>m;
    for(int i=0;i<N;i++){
        cin>>f[i].a>>f[i].b;
    }

    int l=1,r=N;
    while(l<r){
        int mid=l+r+1>>1;
        if(check(mid))l=mid;
        else{r=mid-1;}
    }
  cout<<l<<endl;
}

题目描述
输入一个n行m列的整数矩阵,再输入q个询问,每个询问包含四个整数x1, y1, x2, y2,表示一个子矩阵的左上角坐标和右下角坐标。

对于每个询问输出子矩阵中所有数的和。

输入格式
第一行包含三个整数n,m,q。

接下来n行,每行包含m个整数,表示整数矩阵。

接下来q行,每行包含四个整数x1, y1, x2, y2,表示一组询问。

输出格式
共q行,每行输出一个询问的结果。

数据范围
1≤n,m≤1000,
1≤q≤200000,
1≤x1≤x2≤n,
1≤y1≤y2≤m,
−1000≤矩阵内元素的值≤1000

输入样例:
3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4

输出样例:
17
27
21

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1010;
int a[N][N],s[N][N];
int m,n,q;
int main(){
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+a[i][j];
        }
    }
   while(q--){
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        int h=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
        cout<<h<<endl;
    }
    
}

前缀和 

输入一个长度为n的整数序列。

接下来再输入m个询问,每个询问输入一对l, r。

对于每个询问,输出原序列中从第l个数到第r个数的和。

输入格式
第一行包含两个整数n和m。

第二行包含n个整数,表示整数数列。

接下来m行,每行包含两个整数l和r,表示一个询问的区间范围。

输出格式
共m行,每行输出一个询问的结果。

数据范围
1≤l≤r≤n,
1≤n,m≤100000,
−1000≤数列中元素的值≤1000
输入样例:
5 3
2 1 3 6 4
1 2
1 3
2 4
输出样例:
3
6
10

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1010;
int a[N],s[N];
int n,q;
int main(){
    cin>>n>>q;
    for(int i=1;i<=n;i++){
            cin>>a[i];
            s[i]=s[i-1]+a[i];
        }
    
   while(q--){
        int x1,y1;
        cin>>x1>>y1;
        int h=s[y1]-s[x1-1];
        cout<<h<<endl;
    }
    
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值