【HDU】5110 Alexandra and COS 分块处理
来源:互联网 发布:sql删除重复行 编辑:程序博客网 时间:2024/06/05 23:02
传送门:【HDU】5110 Alexandra and COS
题目分析:仔细观察题目可以发现,max(abs(xi-xj),abs(yi-yj))其实就等于abs(yi-yj),所以对于一个询问(X,Y,D),其实就是sum{prefix[X-i*D][R]-prefix[X-i*D][L-1] | X-i*D>0,i=0,1,2...... | R = min { X + i * D , m } , L = max { X - i * D , 1 } }我看到这题的反应就是可以分块做- -……
D>sqrt(n)的我们暴力就好。
D<=sqrt(n)的,我们可以预处理,用ans[D][X][Y]表示询问(X,Y,D)的答案。
处理处左前缀三角形,右前缀三角形,矩阵前缀和,然后三者容斥一下就是答案。
具体呢可以看代码。
我一开始是建立很多个三维数组,然后先X,后Y,再D的顺序求解。但这样内存是不够的,可以发现,首先枚举D,然后再是(X,Y),因为只有解是我们要保存的,中间每次都是重新算,于是只要二维的数组保存中间求的各个前缀信息就好了。
如果所有的数据都按照上面的去做,TLE是一定的!虽然max{N*M,Q}>1000的只有三组,但每次预处理的复杂度还是在的。于是我们可以对数据分两种情况:Q>1000的我们用上述方法求解,Q<=1000的我们直接暴力!
稍微计算一下复杂度,大的3组,复杂度3*(N*N*sqrt(N)+Q*sqrt(N))=1.425*10^8(M,N,Q取最大,sqrt(N)当作31),小的27组,复杂度27*(Q*N)=2.7*10^7(M,N,Q均取1000),一共约2*10^8次。
这里吐嘈一下数据,极大部分的询问的D是小于等于3的,亲测。也就是说,大于3的暴力,小于等于3的预处理的速度是最快的= =!
还有一点就是寻址问题,我一开始将数组下标与循环没有一一对应,于是TLE无数,最后对应起来后就能AC了。。。不懂计算机内部的优化。。。我真心觉得题目这样算不算卡常数= =寻址的优化都要考虑才可以。。当然我还用了另一种方法AC:用结构体保存解。
代码如下:
#include <set>#include <cmath>#include <vector>#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;typedef long long LL ;#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define clr( a , x ) memset ( a , x , sizeof a )const int MAXN = 1005 ;const int L = 33 ;int G[MAXN][MAXN] ;int down[MAXN][MAXN] ;int prefix[MAXN][MAXN] ;int prefix_dn[MAXN][MAXN] ;int prefix_lt[MAXN][MAXN] ;int prefix_rt[MAXN][MAXN] ;int ans[L][MAXN][MAXN] ;int n , m , q , sqrtD ;char s[MAXN] ;void scanf ( int &x , char c = 0 ) {while ( ( c = getchar () ) < '0' || c > '9' ) ;x = c - '0' ;while ( ( c = getchar () ) >= '0' && c <= '9' ) x = x * 10 + c - '0' ;}void read () {For ( i , 1 , n ) {scanf ( "%s" , s + 1 ) ;For ( j , 1 , m ) {G[i][j] = ( s[j] == 'X' ) ;prefix[i][j] = prefix[i][j - 1] + G[i][j] ;}}}void solve1 () {int x , y , D ;sqrtD = ( int ) sqrt ( ( double ) n ) ;For ( k , 1 , sqrtD ) {For ( i , 1 , n ) {For ( j , 1 , m ) {down[i][j] = G[i][j] ;if ( i - k > 0 ) down[i][j] += down[i - k][j] ;prefix_dn[i][j] = prefix_dn[i][j - 1] + down[i][j] ;prefix_lt[i][j] = down[i][j] ;if ( i - k > 0 ) {if ( j - k <= 0 ) prefix_lt[i][j] += prefix_dn[i - k][j - 1] - prefix_dn[i - k][0] ;else {prefix_lt[i][j] += prefix_dn[i - k][j - 1] - prefix_dn[i - k][j - k] ;prefix_lt[i][j] += prefix_lt[i - k][j - k] ;}}}rev ( j , m , 1 ) {prefix_rt[i][j] = down[i][j] ;if ( i - k > 0 ) {if ( j + k > m ) prefix_rt[i][j] += prefix_dn[i - k][m] - prefix_dn[i - k][j] ;else {prefix_rt[i][j] += prefix_rt[i - k][j + k] ;prefix_rt[i][j] += prefix_dn[i - k][j + k - 1] - prefix_dn[i - k][j] ;}}}For ( j , 1 , m ) ans[k][i][j] = prefix_lt[i][j] + prefix_rt[i][j] - down[i][j] ;}}while ( q -- ) {scanf ( x ) ;scanf ( y ) ;scanf ( D ) ;if ( D <= sqrtD ) {//printf ( "%d %d\n" , prefix_lt[x][y][D] , prefix_rt[x][y][D] ) ;printf ( "%d\n" , ans[D][x][y] ) ;}else {int L = y , R = y , sum = 0 ;while ( x > 0 ) {sum += prefix[x][R] - prefix[x][L - 1] ;x -= D ;L = max ( 1 , L - D ) ;R = min ( m , R + D ) ;}printf ( "%d\n" , sum ) ;}}}void solve2 () {int x , y , D ;while ( q -- ) {scanf ( x ) ;scanf ( y ) ;scanf ( D ) ;int L = y , R = y , sum = 0 ;while ( x > 0 ) {sum += prefix[x][R] - prefix[x][L - 1] ;x -= D ;L = max ( 1 , L - D ) ;R = min ( m , R + D ) ;}printf ( "%d\n" , sum ) ;}}int main () {while ( ~scanf ( "%d%d%d" , &n , &m , &q ) ) {read () ;if ( q > 1000 ) solve1 () ;else solve2 () ;}return 0 ;}
------------------update------------------
我去……竟然把题目看错了……是max(N*M,Q)>1000的只有3组,我看成max(N,M,Q)>1000的只有3组了……这样就不用对Q分类讨论了……
现在如果我对题目做了修改:max(N,M,Q)>1000的最多3组。
这时候如果不分类讨论的话是一定会TLE的(假设30组N,M,Q都是1000,则复杂度就是30*N^2.5=9.1*10^8)。
总的来说,我分类讨论的写法是更好的(图个心理安慰)
- 【HDU】5110 Alexandra and COS 分块处理
- hdu 5110 Alexandra and COS(分块,DP,预处理)
- Hdu 5110 Alexandra and COS(对距离进行分块)
- hdu 5110 Alexandra and COS 压线飘过
- hdu 5110 Alexandra and COS(dp)
- 【BestCoder】 HDOJ 5110 Alexandra and COS
- H电-Problem Archive-5110-Alexandra and COS
- HDU-#5108 Alexandra and Prime Numbers
- HDU 5109 Alexandra and A*B Problem
- HDU 5108 Alexandra and Prime Numbers
- hdu 5109 Alexandra and A*B Problem
- hdu-5108(Alexandra and Prime Numbers)
- hdu 5109 Alexandra and A*B Problem
- hdu_5110_Alexandra and COS(DP+分块思想)
- HDU 5108Alexandra and Prime Numbers(大素数)
- hdu 5108——Alexandra and Prime Numbers
- HDU-5108-Alexandra and Prime Numbers (BestCoder Round #19)
- Hdu 5109 Alexandra and A*B Problem(枚举)
- IntentFilter
- 2、kepler安装tomcat8
- 第13周项目1(4)删除数组中特定元素
- 如何解决java接口访问ZooKeeper时的connectionloss错误
- HDU - 5110(递推)
- 【HDU】5110 Alexandra and COS 分块处理
- 人人都会OSGI--实例讲解OSGI开发
- python 2.x转换成python 3.x
- 日语学习之沪江N4基础 20141123 -6
- Elasticsearch的javaAPI之Query DSL-filters
- 第13周项目1-数组大折腾(2)
- cocos2d-js 3.0 单选按钮
- 我爱我家
- 第13周项目5-字符串操作(1)-字母A