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);
}
原文地址:https://www.cnblogs.com/chasedeath/p/13632347.html