三体攻击(蓝桥杯省赛2018C/C++A组第七题) 前缀和与差分优化
2022/2/9 22:42:33
本文主要是介绍三体攻击(蓝桥杯省赛2018C/C++A组第七题) 前缀和与差分优化,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
题目:
题目描述:略
输入输出样例
示例
输入
2 2 2 3
1 1 1 1 1 1 1 1
1 2 1 2 1 1 1
1 1 1 2 1 2 1
1 1 1 1 1 1 2
输出
2
思路:
前置知识:前缀和与差分上、前缀与差分下
三维前缀和公式:
S(x,y,z) = b(x,y,z) + S(x-1,y,z) + S(x,y-1,z) - S(x-1,y-1,z) + S(x,y,z-1) - S(x-1,y,z-1) - S(x,y-1,z-1) + S(x-1,y-1,z-1) 方便记忆: S(X,Y,Z)括号里面的"-"位置由二进制的"1"位置决定 加减运算符号由二进制总数"1"决定,若为奇数就(+)、为偶数就(-) S(X, Y, Z) = a(X, Y, Z) + 表示 001 符号:+ S(X, Y, Z - 1) 010 符号:+ S(X, Y - 1, Z) 011 符号:- S(X, Y - 1, Z - 1) 100 符号:+ S(X - 1, Y, Z) 101 符号:- S(X - 1, Y, Z - 1) 110 符号:- S(X - 1, Y - 1, Z) 111 符号:+ S(X - 1, Y - 1, Z - 1)
三维差分操作 给(x1,y1,z1) 到 (x2,y2,z2) 加 h
void insert(int x1,int y1,int z1,int x2,int y2,int z2,int h) {//对b数组执行插入操作,等价于对a数组中的(x1,y1,z1)到(x2,y2,z2)之间的元素都加上了h b(x1, y1, z1) +=h b(x1, y1, z2+1) -=h b(x1, y2+1, z1) -=h b(x1, y2+1, z2+1) +=h b(x2+1, y1, z1) -=h b(x2+1, y1, z2+1) +=h b(x2+1, y2+1, z1) +=h b(x2+1, y2+1, z2+1) -=h }
代码:
#include<iostream> #include<cstring> using namespace std; typedef long long LL; const LL N=2e6+10; int A,B,C,m;// 声明第一行参数, A层 B行 C列 m轮攻击 LL s[N],b[N],bS[N];// 声明战舰防御值数组、差分数组、前缀和数组 // 定义存放每轮攻击的7个参数结构体 struct Atk{ int x1,y1,z1,x2,y2,z2,h; }atk[N]; // 三维转为一维表示 int getindex(int i,int j,int k){ return ((i - 1)*B + (j -1))*C + k; } // 三维差分操作 void insert(LL b[],int x1,int y1,int z1,int x2,int y2,int z2,int h){ b[getindex(x1,y1,z1)] += h; b[getindex(x1,y1,z2+1)] -= h; b[getindex(x1,y2+1,z1)] -= h; b[getindex(x1,y2+1,z2+1)] += h; b[getindex(x2+1,y1,z1)] -= h; b[getindex(x2+1,y1,z2+1)] += h; b[getindex(x2+1,y2+1,z1)] += h; b[getindex(x2+1,y2+1,z2+1)] -= h; } // 检查是否爆炸函数 // 将1~t轮攻击进行差分操作 // 进行前缀和操作并判断 int check(int t){ memcpy(bS,b,sizeof(bS));//将b赋值给bS for(int i=1;i <= t;i++){ //构造差分函数 insert(bS,atk[i].x1,atk[i].y1,atk[i].z1,atk[i].x2,atk[i].y2,atk[i].z2,atk[i].h); } for(int i = 1;i <= A;i++){ for(int j = 1;j <= B;j++){ for(int k = 1; k <= C; k++){//前缀和操作 bS[getindex(i,j,k)] += bS[getindex(i,j,k -1)]; bS[getindex(i,j,k)] += bS[getindex(i,j-1,k)]; bS[getindex(i,j,k)] -= bS[getindex(i,j-1,k -1)]; bS[getindex(i,j,k)] += bS[getindex(i-1,j,k)]; bS[getindex(i,j,k)] -= bS[getindex(i-1,j,k -1)]; bS[getindex(i,j,k)] -= bS[getindex(i-1,j-1,k)]; bS[getindex(i,j,k)] += bS[getindex(i-1,j-1,k -1)]; // cout<<bS[getindex(i,j,k)]<<endl; if(bS[getindex(i,j,k)] < 0){ return 1; } } } } return 0; } int main() { cin>>A>>B>>C>>m; // 给大立方体的每个小方格赋值给防御值的同时初始化差分数组 for(int i = 1;i <= A;i++){ for(int j = 1;j <= B;j++){ for(int k = 1; k <= C; k++){ cin>>s[getindex(i,j,k)];//将三维坐标转为一维数组,同时初始化给防御值数组s[N] insert(b,i,j,k,i,j,k,s[getindex(i,j,k)]); } } } // 接收每次攻击时的7个参数 for(int i=1; i <= m;i++){ int x1,y1,z1,x2,y2,z2,h; //该死,这输入顺序bug调了半天 cin>>x1>>x2>>y1>>y2>>z1>>z2>>h; atk[i] = {x1,y1,z1,x2,y2,z2,-h}; } // 二分法进行判断是否爆炸 int l=1,r=m; while(l < r){ int mid = (l + r) >> 1; if(check(mid)){ r = mid; }else{ l = mid + 1; } } std::cout << l << std::endl;//最后l是等于r return 0; }
知识点总结:
- 三维前缀和
- 三维差分操作
- 二分查找
这篇关于三体攻击(蓝桥杯省赛2018C/C++A组第七题) 前缀和与差分优化的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享