“飞行员兄弟”这个游戏,需要玩家顺利的打开一个拥有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 块巧克力分给小朋友们。切出的巧克力需要满足:
-
形状是正方形,边长是整数。
-
大小相同。
例如一块 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;
}
}