zoukankan      html  css  js  c++  java
  • HDU5110:Alexandra and COS(分块+容斥)

    传送门

    题意

    给出(n*m)的矩阵,'X'代表treasure.(q)个询问,每次询问(x,y)且频率为d的潜艇能探索到多少财富。探索范围要求abs(x1-x)>=abs(y1-y),也就是左斜方/右斜方(45°),而且要求(max(abs(x1-x),abs(y1-y)))为d的倍数

    分析

    本题直接预处理每个点的复杂度为(O(nmn)),会TLE,考虑分块,将(d<sqrt{n})的点进行预处理,复杂度为(O(nmsqrt{n})),其余点直接暴力算,复杂度为(O(sqrt{n})),而预处理的方法我是从sio_five学到的,不同于复杂的状态转移,而,是采用右三角形-左三角形的方法,代码简短,十分精妙

    trick

    1.有一点需要注意,如果数组下标未与循环相对应,会TLE,与ac相差3+s,有claris的说法,未对应导致物理不连续,进而导致寻址慢,以后要注意

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    #define F(i,a,b) for(int i=a;i<=b;++i)
    #define R(i,a,b) for(int i=a;i<b;++i)
    #define mem(a,b) memset(a,b,sizeof(a))
    const int N = 1010;
    int n,m,q,x,y,d,B;
    int sum[N][N],g[33][N][N],sa[N][33],gl[N][N],gr[N][N];
    //sum[i][j]记录第i行的前j个和,sa[i][j]记录前i行间距为j的行和,比如sa[3][2]=sum[3][m]+sum[1][m]
    //gl[i][j]记录以(i,j)为边界的左三角形,gr[i][j]记录以(i,j)为边界的右三角形
    char s[N][N];
    void init()
    {
        F(i,1,n)F(j,1,B)
        {
            if(i<j) sa[i][j]=sum[i][m];
            else sa[i][j]=sa[i-j][j]+sum[i][m];
        }
        F(k,1,B)F(i,1,n)F(j,1,m)
        {
            //gl
            if(i<=k||j<=k) gl[i][j]=sum[i][j];
            else gl[i][j]=gl[i-k][j-k]+sum[i][j];
            //gr
            if(i<=k) gr[i][j]=sum[i][j];
            else if(j+k>m) gr[i][j]=sa[i-k][k]+sum[i][j];
            else gr[i][j]=gr[i-k][j+k]+sum[i][j];
            //g
            g[k][i][j]=gr[i][j]-gl[i][j-1];
        }
    }
    void solve()
    {
        int ans=0;
        for(int i=x;i>0;i-=d)
        {
            int l=max(1,y-x+i),r=min(m,y+x-i);
            ans+=sum[i][r]-sum[i][l-1];
        }
        printf("%d
    ",ans);
    }
    int main()
    {
        while(scanf("%d %d %d",&n,&m,&q)!=EOF)
        {
            F(i,1,n)
            {
                scanf("%s",s[i]+1);
                F(j,1,m) sum[i][j]=sum[i][j-1]+(s[i][j]=='X');
            }
            B=sqrt(n);
            init();
            while(q--)
            {
                scanf("%d %d %d",&x,&y,&d);
                if(d<=B) printf("%d
    ",g[d][x][y]);
                else solve(); 
            }
        }
        return 0;
    }
    
  • 相关阅读:
    直接插入排序
    合并排序--分治法思想
    scanf printf函数返回值
    转自CSDN,关于状态机
    关于制表符
    网上找的一篇博文,原文搞错了,应该是 ,本文已改正!——回车CR和换行line feed
    再看c语言之getchar/putchar
    使用FL2440之问题1
    Java:String、StringBuffer和StringBuilder的区别
    编译哈工大语言技术平台云LTP(C++)源码及LTP4J(Java)源码
  • 原文地址:https://www.cnblogs.com/chendl111/p/7096477.html
Copyright © 2011-2022 走看看