zoukankan      html  css  js  c++  java
  • hdu_5110_Alexandra and COS(DP+分块思想)

    题目连接:hdu_5110_Alexandra and COS

    题意:

    给你一个图,X代表宝藏,然后有一个船,它的声纳的频率为D,定船到宝藏的距离为Dis=max(abs(x1-x2),abs(y1-y2)),如果D是Dis的约数并且宝藏在船的上方开角45°,那么这个船就能探测到这个宝藏,现在给你q个询问,每一个询问有一个位置x,y和一个声纳的频率D,问这个船能探测到多少宝藏

    题解:

    因为是45°角,所以Dis实际就是abs(y1-y2),然后我们可以对每一个D,DP它45°开角满足条件的前缀和,不过对每一个D都这样做,那肯定超时,仔细想想,D越大,直接暴力搜肯定会比DP来的快,因为直接暴力我们可以每次跳D格来找,所以这里我们就要分块,一般分为sqr=sqrt(n),不过这里我亲测出数据好像当sqr=3时,跑的速度更快,然后我就直接分为D>3和D<=3来做

    这里DP的方程为:设dp[i][j][k]为第i行,第j列,声纳频率为k的开角45°满足条件的前缀和,状态转移方程为dp[i][j][k]=dp[i-k][j-k][k]+dp[i-k][j+k][k]-dp[i-2*k][j][k]+第(i-k)行中[j-k,j+k]满足条件的点

    (没装画图软件,画的有点丑,将就看)下面以D为2时举例,假设我们要查询x=5,y=3这个点,红色的代表满足条件的点,蓝色的线代表范围,我们可以看到粉圈内的点加了两次,所以要减掉,对应的范围就是dp[i-2*k][j][k]


     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define F(i,a,b) for(int i=a;i<=b;++i)
     5 using namespace std;
     6 
     7 const int N=1007;
     8 int dp[N][N][4],g[N][N],n,m,q;
     9 char in[N][N];
    10  
    11 int main(){
    12     while(~scanf("%d%d%d",&n,&m,&q)){
    13         F(i,1,n)scanf("%s",in[i]+1);
    14         F(i,1,n)F(j,1,m)g[i][j]=g[i][j-1]+(in[i][j]=='X');
    15         for(int i=1,*p,kk;i<=n;++i)F(j,1,m)F(k,1,3){
    16             p=&dp[i][j][k],*p=(in[i][j]=='X'),kk=k<<1;
    17             if(i>k){        
    18                 if(j>k)*p+=dp[i-k][j-k][k]+g[i-k][j]-g[i-k][j-k];
    19                 else{
    20                     *p+=g[i-k][j];
    21                     if(i>kk)*p+=dp[i-kk][j][k]+g[i-kk][j-1];
    22                 }
    23                 if(j+k<=m)*p+=dp[i-k][j+k][k]+g[i-k][j+k-1]-g[i-k][j];
    24                 else{
    25                     *p+=g[i-k][m]-g[i-k][j];
    26                     if(i>kk)*p+=dp[i-kk][j][k]+g[i-kk][m]-g[i-kk][j];
    27                 }
    28                 if(i>kk)*p-=dp[i-kk][j][k];
    29             }
    30         }
    31         for(int i=1,c,r,w,ret;i<=q;i++){
    32             scanf("%d%d%d",&r,&c,&w);
    33             if(w>3){
    34                 ret=0;
    35                 for(int j=r,lf=c,rt=c;j>0;j-=w,lf=max(lf-w,1),rt=min(m,rt+w))
    36                     ret+=g[j][rt]-g[j][lf-1];
    37                 printf("%d
    ",ret);
    38             }else printf("%d
    ",dp[r][c][w]);
    39         }
    40     }
    41     return 0;
    42 }
    View Code



  • 相关阅读:
    double 和 int 同时存在时的运算
    快速排序
    案例:商品放大镜效果
    淘宝flexible.js源码分析
    案例:模态框拖拽
    Web APIs——BOM
    案例:获取URL参数数据
    案例:5秒之后自动跳转页面
    JS中this指针的指向
    按钮:点击发送短信按钮60秒内不能再次点击的功能
  • 原文地址:https://www.cnblogs.com/bin-gege/p/5696090.html
Copyright © 2011-2022 走看看