zoukankan      html  css  js  c++  java
  • COCI2016/2017 Contest#3 F Meksikanac

    COCI2016/2017 Contest#3 F Meksikanac

    (M=maxlbrace X_p,Y_p brace)

    分析:

    给定的多边形很难直接处理

    如果直接枚举平移位置,然后判断每个点是否在多边形内部

    由于不是凸包,判断点的位置可以用1.射线法,2.转角判断是否是360

    一次判断复杂度为(O(K)),因此复杂度为(O(M^2cdot Ncdot K)),显然不可取

    但是观察题目的条件,不管怎么移动,多边形都只包含一些整点

    由于多边形内的整点只有 (O(M^2)) 个,如果能全部求出,直接匹配判断会方便很多,且复杂度降为(O(M^4))

    那么如何求出多边形内部的整点?

    做法1

    考虑枚举每个点,暴力判断,复杂度为(O(M^2K))

    做法2

    考虑枚举(x)一维,像写扫描线一样,把所有合法的(y)扫描出来(跨过奇数次在内部)

    复杂度为(O(MKlog K))或者可能(O(MK))

    [ ]

    优化

    发现转化后,问题变为了 :

    给定点集(A,B),判断将(A)点集平移((dx,dy))后,是否存在点与(B)中重合

    考虑这个问题的一维情形:

    在给定的数轴上的([0,M])内部有(A,B)两个数集

    那么出现重合的平移量即(B_i-A_j),这个问题可以用一次卷积解决,复杂度为(O(Mlog M))

    [ ]

    类似的,将(x,y)两维压在一起,做类似的卷积就可以判断((dx,dy))是否合法了

    复杂度为(O(M^2log M^2)=O(M^2log M))

    实现上的话,把((x,y))变为(xcdot (y_p+2)+y)即可

    注意这里的减法向下溢出没有关系,因为溢出的部分恰好不会被调用到

    [ ]

    综上,总复杂度为(O(KM+M^2log M))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define reg register
    #define Mod1(x) ((x>=P)&&(x-=P))
    #define Mod2(x) ((x<0)&&(x+=P))
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
    template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
    char IO;
    int rd(){
        int s=0,f=0;
        while(!isdigit(IO=getchar())) if(IO=='-') f=1;
        do s=(s<<1)+(s<<3)+(IO^'0');
        while(isdigit(IO=getchar()));
        return f?-s:s;
    }
     
    const int N=510,M=10010,P=998244353;
    const double eps=1e-9;
     
    int X,Y,D,n,m;
    struct Point{
        int x,y;
        void Read(){ x=rd(), y=rd(); }
    } A[M];
     
    const int K=N*N*4.2;
    int F[K],G[K];
    double U[M];
    int cnt,rev[K];
    ll qpow(ll x,ll k=P-2) {
        ll res=1;
        for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
        return res;
    }
    void NTT(int n,int *a,int f){
        static int e[K>>1];
        rep(i,1,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
        e[0]=1;
        for(int i=1;i<n;i<<=1) {
            int w=qpow(f==1?3:(P+1)/3,(P-1)/i/2);
            for(int j=i-2;j>=0;j-=2) e[j+1]=1ll*(e[j]=e[j>>1])*w%P;
            for(int l=0;l<n;l+=i*2) {
                for(int j=l;j<l+i;++j) {
                    int t=1ll*a[j+i]*e[j-l]%P;
                    a[j+i]=a[j]-t,Mod2(a[j+i]);
                    a[j]+=t,Mod1(a[j]);
                }
            }
        }
        if(f==-1) {
            ll base=qpow(n);
            rep(i,0,n-1) a[i]=a[i]*base%P;
        }
    }
     
    void Cover(int x,int y){
        F[(X+1-x)*D+Y-y]=1;
    }
     
     
    int main(){
        X=rd(),Y=rd(),D=Y+2;
        rep(i,1,n=rd()) {
            int x=rd(),y=rd();
            G[x*D+y]=1;
        }
        int mix=1e9,miy=1e9,max=-1e9,may=-1e9;
        rep(i,1,m=rd()) {
            A[i].Read();
            cmin(mix,A[i].x),cmax(max,A[i].x);
            cmin(miy,A[i].y),cmax(may,A[i].y);
        }
        max-=mix,may-=miy;
        if(max>X || may>Y) return puts("0"),0;
        rep(i,1,m) A[i].x-=mix,A[i].y-=miy;
        A[m+1]=A[1];
        rep(i,0,X) {
            cnt=0;
            rep(j,1,m) {
                Point L=A[j],R=A[j+1];
                if(L.x>R.x) swap(L,R);
                if(i<L.x || i>R.x) continue;
                if(L.x==R.x) {
                    rep(y,min(L.y,R.y),::max(L.y,R.y)) Cover(i,y);
                    continue;
                }
                double y=1.0*(R.y-L.y)/(R.x-L.x)*(i-L.x)+L.y;
                if(i<R.x) U[++cnt]=y;
                if(abs(y-int(y))<eps) Cover(i,y);
            }
             
            sort(U+1,U+cnt+1);
            for(int j=1;j<=cnt;j+=2) for(int y=ceil(U[j]);y<=U[j+1]+eps;++y) Cover(i,y);
        }
     
        int R=1,cc=-1;
        while(R<=(X+1)*2*D) R<<=1,cc++;
        rep(i,1,R-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<cc);
        NTT(R,F,1),NTT(R,G,1);
        rep(i,0,R-1) F[i]=1ll*F[i]*G[i]%P;
        NTT(R,F,-1);
        int ans=0;
        rep(i,0,X-max) rep(j,0,Y-may) if(!F[(X+1+i)*D+Y+j]) ans++;
        printf("%d
    ",ans);
    }
    
  • 相关阅读:
    【移动开发】Android应用程序中实用的代码框架(二)
    使用ListView应该注意的地方
    使用ListView应该注意的地方
    web技术文章
    [LeetCode] 565. Array Nesting
    [LeetCode]495. Teemo Attacking
    south 命令学习
    关于access_token过期的解决办法
    决策树总结《一》.md
    crontab命令
  • 原文地址:https://www.cnblogs.com/chasedeath/p/13632347.html
Copyright © 2011-2022 走看看