HDU-6381

题目:

度度熊最喜欢六边形的网格了!!!

上图由左至右依序是边长为 11, 22 以及 33 的六边形网格。

另外,每个六边形网格最左侧的格子称之为这个六边形网格的锚点,上图中每个六边形网格的锚点都以蓝色着色。

定义在六边形网格上的坐标系统:相对一个坐标为 (x,y)(x,y) 的中心格子,其周围格子的坐标定义为下图中所示的值:

给定一个大小为 LL 的六边形主网格,这个六边形主网格的锚点的坐标为 (1,L)(1,L)。这个主网格中每一个格子上都有一个颜色,以 00 至 6161 之间的整数代表。对于这个主网格有 QQ 个询问,每个询问将会询问这个主网格中某一个六边形子网格的范围中,包含有几个不一样的颜色。

一个询问以三个整数 <x,y,l><x,y,l> 来表示其中一个六边形的子网格,依序为其锚点的坐标 (x,y)(x,y) 以及其大小 ll。例如,下图为一个大小 L=3L=3 的主网格,格子内部的数字为其坐标,而非格子的颜色。绿色边框所包围的子网格是一个锚点坐标为 (5,3)(5,3),大小 l=2l=2 的子网格,以 <5,3,2><5,3,2> 表示,同时,红色边框表示 <3,1,1><3,1,1> 的子网格。

Input

输入的第一行有一个正整数 TT,代表接下来有几笔测试资料。

对于每笔测试资料: 第一行有一个正整数 LL。 接下来的 2L−12L−1 行输入代表一个大小为 LL 的六边形网格。 六边形网格将会透过下列的过程转换至输入的格式:

  1. 将每格内代表颜色的数字 00~6161 按照 0-9a-zA-Z 的顺序对照转换为一个字符,例如 1010 转换为 'a',而 3636 转换为 'A'。
  2. 将每行中的字符由左至右串接起来形成一个字符串,注意两个字符之间并不会安插任何的空格符。
  3. 输入中的 2L−12L−1 行每行会有一个字符串,依序代表编码后由上至下的这 2L−12L−1 个字符串。

接下来的一行有一个整数 QQ 代表接下来有几组询问。 接下来的 QQ 行每行有三个正整数 xx, yy 及 ll,代表一组询问 <x,y,l><x,y,l>。

下图为范例测试资料中的六边形网格,格子内显示的数字代表颜色,而非坐标:

  • 1≤L≤2501≤L≤250
  • 代表六边形网格的字符串中只会有 0-9a-zA-Z 这些字符。
  • 0≤Q≤3×1050≤Q≤3×10​5​​
  • 1≤x≤4L−31≤x≤4L−3
  • 1≤y≤2L−11≤y≤2L−1
  • 1≤l≤L1≤l≤L
  • (x,y)(x,y) 一定是给定的六边形网格中合法的格子点。
  • <x,y,l><x,y,l> 询问的子六边形网格一定完整的位于主网格中。
  • 1≤T≤151≤T≤15
  • 至多 11 笔测试资料中的 L>50L>50
  • 至多 11 笔测试资料中的 Q>1000Q>1000

Output

对于每一笔测试资料,对于每一个询问,请依序各自在一行内输出一个整数,代表此询问的答案。 两笔测试资料间请不要输出多余的空白行。

Sample Input

1
3
012
3456
789ab
cdef
ghi
10
1 3 1
1 3 2
1 3 3
9 3 1
7 3 1
3 3 1
3 3 2
5 3 1
5 3 2
2 2 2

Sample Output

1
7
19
1
1
1
7
1
7
7

(题目复制过来后部分文本重复了)

题目看起来很长,加上有那么多六边形好像很麻烦,但其实根本问题还是:

给一组东西,多次询问某个范围,求这个范围内的某个/某种值。

符合rmq的条件,所以可以尝试用rmq解决。

这道题其实可以算是资格赛1002的进阶版,同样使用rmq算法,只不过那道题给的是一个数组,求的是最值,这里给的是一组六边形,求的是颜色的种数。

rmq算法用到了动态规划,那么就要有状态。

题目的63个颜色可以用63个二进制表示,出现哪种颜色,哪一位用“1”表示,有点类似资格赛1001的思路。可以用long long 类型的数来表示每组六边形的状态。

long long dp [2*MAXL-1] [4*MAXL-3] [9]

dp [i] [j] [k] 表示以点(i,j)为锚点,边长为 2的k次方 的六边形的状态(所包含的颜色)。

状态转移:

rmq算法是以2倍增的思想来不断进行处理的,对应这道题也就是:对于边长为2的k次方的六边形,用边长为2的(k-1)次方的六边形来覆盖处理它。

以边长为2的六边形来看,我们可以用6个点对应的6个边长为1的六边形 + 中心六边形来覆盖它;

当边长=2^k >2时,同样的,6个点对应的6个2^(k-1) 个六边形 + 中心六边形可以表示它。(这里的六边形会有重叠的部分,但不会有遗漏的部分)

为了方便放进数组,先将题目中给出的坐标表示换一下位置,比如题目中(1,3)的点我们表示成(3,1)放进六边形数组six[3][1]。

所以接下来就是确定这7个六边形的锚点的问题了。

可以自己动手再画一个边长为4的六边形,对比边长为2,边长为1的六边形,多利用2^k,2^(k-1),2^(k+1)不难得出七个六边形的锚点坐标:

/**七个六边形位置:1        23       7       45        6*/              int i1 = i-(1<<(k-1));int j1 = j + (1<<(k-1));int i2 = i - (1<<(k-1));int j2 = j + (1<<(k-1)) + (1<<k);int i3 = i;int j3 = j;int i4 = i;int j4 = j + (1<<(k+1));int i5 = i + (1<<(k-1));int j5 = j + (1<<(k-1));int i6 = i + (1<<(k-1));int j6 = j + (1<<(k-1)) + (1<<k);int i7 = i;int j7 = j + (1<<(k+1)) - 2;

所以,

状态转移方程:

dp[i][j][k] = dp[i1][j1][k-1] | dp[i2][j2][k-1]  | dp[i3][j3][k-1] | dp[i4][j4][k-1]  | dp[i5][j5][k-1] | dp[i6][j6][k-1]  | dp[i7][j7][k-1];

也就是这7个六边形做 按位或( | )操作 —— 有1为1,全0为0,这个运算就可以来表示这七个六边形组合在一起的颜色情况了。

初始状态:

k=0,只有一个六边形,它的状态就是它本身的颜色。

dp[i][j][0] = (long long)1<<six[i][j]

dp数组存储完之后,剩下的就是查询了。

由于rmq用的是2的倍增,在这道题中也就是计算了1,2,4,8 ... 边长的颜色情况,那么对于3,5,6,7这些边长没办法直接在dp数组里面找到,所以查询仍然是分段查询。同样的道理比如资格赛1002。

先打表,求一下0-250这些数的log2是多少,存储在Log2数组中。(这里存储的时候是向下取整,也就是说log2(3) = 1)

然后,在查询时,我们只需要6个顶点对应的六边形就可以覆盖待查询的六边形了,因为中心六边形肯定包括在这个6个中。

设查询的边长为L,Log2[L] = k;

查询区间的确定,实际上是与 (L - 2^k)有关,可以得到六个六边形的锚点坐标,并进而得到这六个六边形组成的颜色情况n:

 long long n;int temp = l - (1<<k);     // L - 2^kint i1 = x - temp;int j1 = y + temp;int i2 = x - temp;int j2 = y + 3 * temp;int i3 = x;int j3 = y;int i4 = x;int j4 = y + 4 * temp;int i5 = x + temp;int j5 = y + temp;int i6 = x + temp;int j6 = y + 3 * temp;n = (long long)dp[i1][j1][k] | dp[i2][j2][k]| dp[i3][j3][k] | dp[i4][j4][k]| dp[i5][j5][k] | dp[i6][j6][k];

最后,只要数一下 n 里面有多少个1,那么就有多少种颜色,就是答案了。

代码:

//
//  main.cpp
//  初赛B1002
//
//  Created by jinyu on 2018/8/13.
//  Copyright © 2018年 jinyu. All rights reserved.
//#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;/**L  ,  L 个    :   1L-1,  L+1    :   2L-2,  L+2    :   3...          :   ...1  ,  2L-1   :   ...2  ,  2L-2   :3  ,  2L-3   :...          :L  ,  L      :   2L-1*/const int MAXL = 250+7;int six[2*MAXL-1][4*MAXL-3];
int L;
long long dp[2*MAXL-1][4*MAXL-3][9];
int Log2[MAXL];void rmq(){for(int k = 1;(1<<k)<=L;k++){for(int i = 1;i+(1<<(k-1))<=2*L-1;i++){for(int j = 1;j+(1<<(k-1))+(1<<k)<=4*L-3;j++){if(six[i][j]==-1)continue;if((i-(1<<(k-1)))<1)continue;int i1 = i-(1<<(k-1));int j1 = j + (1<<(k-1));int i2 = i - (1<<(k-1));int j2 = j + (1<<(k-1)) + (1<<k);int i3 = i;int j3 = j;int i4 = i;int j4 = j + (1<<(k+1));int i5 = i + (1<<(k-1));int j5 = j + (1<<(k-1));int i6 = i + (1<<(k-1));int j6 = j + (1<<(k-1)) + (1<<k);int i7 = i;int j7 = j + (1<<(k+1)) - 2;dp[i][j][k] = dp[i1][j1][k-1] | dp[i2][j2][k-1]| dp[i3][j3][k-1] | dp[i4][j4][k-1]| dp[i5][j5][k-1] | dp[i6][j6][k-1]| dp[i7][j7][k-1];}}}
}int query(int x,int y,int l){int k = Log2[l];int temp = l - (1<<k);if(k==0)return 1;long long n;int i1 = x - temp;int j1 = y + temp;int i2 = x - temp;int j2 = y + 3 * temp;int i3 = x;int j3 = y;int i4 = x;int j4 = y + 4 * temp;int i5 = x + temp;int j5 = y + temp;int i6 = x + temp;int j6 = y + 3 * temp;n = (long long)dp[i1][j1][k] | dp[i2][j2][k]| dp[i3][j3][k] | dp[i4][j4][k]| dp[i5][j5][k] | dp[i6][j6][k];int ans = 0;//判断n中1的个数while(n){n = n & (n-1);ans++;}return ans;
}int main(){for(int i = 0;i<MAXL;i++){Log2[i] = i==0?-1:Log2[i>>1]+1;}int T;scanf("%d",&T);while(T--){scanf("%d",&L);for(int i = 0;i<4*L+7;i++){for(int j = 0;j<4*L+7;j++)six[i][j] = -1;}getchar();char c;int k = 1;for(int i = L;i>=1;--i){int tempi = i;int num = L+(L-i);while(num--){c = getchar();if(c>='0' && c<='9'){six[k][tempi] = c-'0';}else if(c>='a' && c<='z'){six[k][tempi] = c-'a'+10;}else if(c>='A' && c<='Z'){six[k][tempi] = c-'A'+36;}tempi+=2;}getchar();k++;}for(int i = 2;i<=L;++i){int tempi = i;int num = L+(L-i);while(num--){c = getchar();if(c>='0' && c<='9'){six[k][tempi] = c-'0';}else if(c>='a' && c<='z'){six[k][tempi] = c-'a'+10;}else if(c>='A' && c<='Z'){six[k][tempi] = c-'A'+36;}tempi+=2;}getchar();k++;}//        for(int i = 1;i<=2*L-1;i++){
//            for(int j = 1;j<=4*L-3;j++)
//            {
//                if(six[i][j]==-1)
//                    cout<<" ";
//                else
//                    cout<<six[i][j]<<" ";
//            }
//            cout<<endl;
//        }for(int i = 1;i<=2*L-1;i++){for(int j = 1;j<=4*L-3;j++){if(six[i][j]==-1)dp[i][j][0] = (long long)0;elsedp[i][j][0] = (long long)1<<six[i][j];}}rmq();int Q;scanf("%d",&Q);while(Q--){int x,y,l;scanf("%d%d%d",&y,&x,&l);printf("%d\n",query(x,y,l));}//        printf("3 1 1 : %lld\n",dp[3][1][1]);}return 0;
}

2018百度之星程序设计大赛初赛B——1002hex相关推荐

  1. hdu6383(2018 “百度之星”程序设计大赛 - 初赛(B))

    p1m2 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Sub ...

  2. hdu6380(2018 “百度之星”程序设计大赛 - 初赛(B))

    degree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total S ...

  3. hdu6375(2018 “百度之星”程序设计大赛 - 初赛(A))

    度度熊学队列 Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total S ...

  4. 2018 “百度之星”程序设计大赛 - 初赛(A)

    hdu6374                         度度熊拼三角 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536 ...

  5. 2018 “百度之星”程序设计大赛 - 初赛(A)P1002度度熊学队列(双端队列模拟,STL)

    problem 度度熊正在学习双端队列,他对其翻转和合并产生了很大的兴趣. 初始时有 N 个空的双端队列(编号为 1 到 N ),你要支持度度熊的 Q 次操作. ①1 u w val 在编号为 u 的 ...

  6. 2018 “百度之星”程序设计大赛 - 初赛(A)P1001度度熊拼三角(贪心)

    problem 给定n根棍子.在其中选三根拼成最大周长三角形的周长.不能拼出三角形输出-1. solution 先对数组进行排序,并利用贪心算法先取得最长的一根棍子,之后的两根依次取最长的棍子,如果这 ...

  7. 2018 “百度之星”程序设计大赛 - 初赛(B)Pro.1001 degree

    题目链接 至多删k条边,自由添边保证无环,求最大度数. 找出度数最大的度数值ans,再利用并查集求出集合数sum,加k时判断是否大于n-1即可. #include<cstdio> #inc ...

  8. 【2018百度之星程序设计大赛初赛】rect

    Problem Description 度度熊有一个大小为 MX×MYMX×MYMX \times MY 的矩形,左下角坐标为 (0,0)(0,0)(0, 0),右上角坐标为 (MX,MY)(MX,M ...

  9. HDU 6114 Chess 【组合数】(2017百度之星程序设计大赛 - 初赛(B))

    Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  10. 2018百度之星程序设计大赛 - 资格赛 hdu6345(找区间最小值)

    子串查询 Time Limit: 3500/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Sub ...

最新文章

  1. 两次服务器灾难事故的反思
  2. 真是O(1)吗?想清楚了没?
  3. 快速排序算法_常用排序算法之快速排序
  4. python爬虫面试问题_Python爬虫面试总结
  5. LeetCode 1497. 检查数组对是否可以被 k 整除(余数配对)
  6. kindle刷机ttl_#原创新人#艰难的TTL刷机路--新固件斐讯 K1 无线路由刷机教程
  7. 2007所做更改会影响共用模板normal
  8. 文件被后台程序占用无法删除_Windows系统中,教你彻底删除C盘的顽固文件,瞬间多出10个G...
  9. linux驱动开发 ST7789 LCD驱动移植(I.MX6ULL平台)
  10. 单片机内存及运行原理
  11. HTML超链接引用到地图,HTML超链接
  12. UCan技术开放日|告别转型“焦虑”,从云原生开始
  13. obs多推流地址_OBS下载、安装、使用(腾讯)推流直播教程
  14. Topic ods_base_db not present in metadata after 60000 ms.
  15. opengl高级光照之延迟渲染以及光体积
  16. Windows 10 安装STF实战
  17. QIL:《Learning to Quantize Deep Networks by Optimizing Quantization Intervals with Task Loss》论文学习
  18. 九宫怎么排列和使用_九宫格排列与浏览的简单功能
  19. 【文献2014】固体火箭发动机中的流固耦合仿真
  20. 找不到适合自己的工作很迷茫怎么办?

热门文章

  1. 计算机图形学基础-第二章 VB.NET 绘图基础
  2. 分布式系统的概念、特点及常见方案
  3. eclipse环境变量的配置
  4. MATLAB/simulink_S函数
  5. MapStruct使用指南
  6. Diamond/Quartus 工具的bug
  7. 在android中编程制作kml、kmz文件的思路
  8. 人脸数据集——亚洲人脸数据集
  9. UTrust4701F双界面NFC读写器读卡器测试软件读写NFC电子标签的文本|网址|电子名片|智能海报|蓝牙地址内容操作说明
  10. 【Unity3D】地形Terrain