2010-1082

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

题意大致是:有N*M格子组成矩形,有K个格子需要从边界出发找一条直线的路让军队进入。从四条边界出发分别有四条,但是只有最短的一条或并列最短的几条是有效的。同时两条路如果相交,只有较短的一条路是有效。

可以考虑把矩形分成东西南北四块,显然根据条件,西块的格子可以从西线进入,南北同理。有一些格子到两边或更多边距离相等的会在不同的块上分别出现。如正中心的格子四块上都有,于是到某格的路线数可以用格子出现的次数表示。

如下图,由相交路线只取最短可知:当西块的某格A出现,与其同一Y坐标,正东方向的西块格子B必须从西块消失,因为A的存在,B格无法从西线进入。可以在西块把待占格子按Y坐标排序,Y坐标相等的只取X坐标最小的,其余全都去掉。

[[Image(au.jpg)]]


东南北块同样处理。南北按X坐标排序,X坐标相等取离边界最近的格子(南块取Y坐标最大,北块取Y坐标最小)。然后统计东西南北四块格子i的出现次数a,,i,,,结果[[Image(http://icpc.watashi.ws/cgi-bin/mathtex.cgi?ans=\prod{a_i})]]。因为结果最大可以到2^10000^左右,需要大数运算处理。

{{{
#!cpp
#include <cstdio>
#include <map>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
struct point
{
    int x,y;
    bool type[4];
    point()
    {
        type[0]=type[1]=type[2]=type[3]=false;
    }
    void output()
    {
        printf("%d-%d ",x,y);
    }
};
struct bignum
{
    int c,n[1000];
    void mul(int p)
    {
        int i;
        if (p==1) return;
        for (i=0;i<c;i++)
            n[i]*=p;
        for (i=0;i<c;i++)
            if (n[i]>10000) 
            {
                n[i+1]+=n[i]/10000;
                n[i]%=10000;
            }
        if (n[c]>0) c++;
    }
    void output()
    {
        int i;
        printf("%d",n[c-1]);

        for (i=c-2;i>=0;i--)
        {
            if (n[i]<1000) printf("0");
            if (n[i]<100) printf("0");
            if (n[i]<10) printf("0");
            printf("%d",n[i]);
        }
        printf("\n");
    }
    void clear()
    {
        memset(n,0,sizeof(n));
        c=1; n[0]=1;
    }
};
vector <int> vp[4];
point p[11000];
int m,n,k,rp,ri;
void build(int ii)
{
    point pt=p[ii];
    int t,i,j;
    int d[4],o[4];
    d[0]=pt.y; o[0]=0;
    d[1]=n-pt.x+1; o[1]=1;
    d[2]=m-pt.y+1; o[2]=2;
    d[3]=pt.x; o[3]=3;
    for (i=0;i<4-1;i++)
        for (j=i+1;j<4;j++)
        {
            if (d[j]<d[i])
            {
                t=d[i]; d[i]=d[j]; d[j]=t;
                t=o[i]; o[i]=o[j]; o[j]=t;
            }
        }
    (vp[o[0]]).push_back(ii);p[ii].type[o[0]]=true;
    if (d[1]==d[0]) {
        p[ii].type[o[1]]=true; 
        vp[o[1]].push_back(ii);
    }
    if (d[2]==d[0]) {p[ii].type[o[2]]=true; vp[o[2]].push_back(ii);}
    if (d[3]==d[0]) {p[ii].type[o[3]]=true; vp[o[3]].push_back(ii);}
}
int cmp0(const int a,const int b)  //North
{
    point *p1=&p[a];
    point *p2=&p[b];
    int ret=p1->x-p2->x;
    if (ret==0) ret=p1->y-p2->y;
    return ret<0;
}
int cmp1(const int a,const int b)  //East
{
    point *p1=&p[a];
    point *p2=&p[b];
    int ret=p1->y-p2->y;
    if (ret==0) ret=p2->x-p1->x;
    return ret<0;
}
int cmp2(const int a,const int b)  //South
{
    point *p1=&p[a];
    point *p2=&p[b];
    int ret=p1->x-p2->x;
    if (ret==0) ret=p2->y-p1->y;
    return ret<0;
}
int cmp3(const int a,const int b)  //West
{
    point *p1=&p[a];
    point *p2=&p[b];
    int ret=p1->y-p2->y;
    if (ret==0) ret=p1->x-p2->x;
    return ret<0;
}
void output()
{
    int i,j;
    for (i=0;i<4;i++)
    {
        for (j=0;j<(int)vp[i].size();j++)
        {
            p[vp[i][j]].output();
        }
        printf("\n");
    }
}
int main()
{
    bignum ans;
    int x,y,i;
    scanf("%d",&rp);
    for (ri=0;ri<rp;ri++)
    {
        memset(p,0,sizeof(p));
        ans.clear();
        for (i=0;i<4;i++) vp[i].clear();
        point t;
        scanf("%d%d",&n,&m);
        scanf("%d",&k);
        for (i=0;i<k;i++)
        {
            scanf("%d%d",&p[i].x,&p[i].y);
            build(i);
        }
        sort(vp[0].begin(),vp[0].end(),cmp0);
        sort(vp[1].begin(),vp[1].end(),cmp1);
        sort(vp[2].begin(),vp[2].end(),cmp2);
        sort(vp[3].begin(),vp[3].end(),cmp3);
        x=y=0;
        for (i=0;i<(int)vp[0].size();i++)
        {
            point *pt=&p[vp[0][i]];
            if (pt->x>x) x=pt->x; else pt->type[0]=false;
        }
        x=y=0;
        for (i=0;i<(int)vp[1].size();i++)
        {
            point *pt=&p[vp[1][i]];
            if (pt->y>y) y=pt->y; else pt->type[1]=false;
        }
        x=y=0;
        for (i=0;i<(int)vp[2].size();i++)
        {
            point *pt=&p[vp[2][i]];
            if (pt->x>x) x=pt->x; else pt->type[2]=false;
        }
        x=y=0;
        for (i=0;i<(int)vp[3].size();i++)
        {
            point *pt=&p[vp[3][i]];
            if (pt->y>y) y=pt->y; else pt->type[3]=false;
        }

        for (i=0;i<k;i++)
        {
            int j,c=0;
            for (j=0;j<4;j++)
                if (p[i].type[j]) c++;
            if (c==0) break;
            ans.mul(c);
        }
        if (i==k) ans.output(); else printf("0\n");
    }
    return 0;
}
}}}
by pxhdg

题意大致是:有N*M格子组成矩形,有K个格子需要从边界出发找一条直线的路让军队进入。从四条边界出发分别有四条,但是只有最短的一条或并列最短的几条是有效的。同时两条路如果相交,只有较短的一条路是有效。

可以考虑把矩形分成东西南北四块,显然根据条件,西块的格子可以从西线进入,南北同理。有一些格子到两边或更多边距离相等的会在不同的块上分别出现。如正中心的格子四块上都有,于是到某格的路线数可以用格子出现的次数表示。

如下图,由相交路线只取最短可知:当西块的某格A出现,与其同一Y坐标,正东方向的西块格子B必须从西块消失,因为A的存在,B格无法从西线进入。可以在西块把待占格子按Y坐标排序,Y坐标相等的只取X坐标最小的,其余全都去掉。

东南北块同样处理。南北按X坐标排序,X坐标相等取离边界最近的格子(南块取Y坐标最大,北块取Y坐标最小)。然后统计东西南北四块格子i的出现次数ai,结果。因为结果最大可以到210000左右,需要大数运算处理。

#include <cstdio>
#include <map>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
struct point
{
    int x,y;
    bool type[4];
    point()
    {
        type[0]=type[1]=type[2]=type[3]=false;
    }
    void output()
    {
        printf("%d-%d ",x,y);
    }
};
struct bignum
{
    int c,n[1000];
    void mul(int p)
    {
        int i;
        if (p==1) return;
        for (i=0;i<c;i++)
            n[i]*=p;
        for (i=0;i<c;i++)
            if (n[i]>10000) 
            {
                n[i+1]+=n[i]/10000;
                n[i]%=10000;
            }
        if (n[c]>0) c++;
    }
    void output()
    {
        int i;
        printf("%d",n[c-1]);
        for (i=c-2;i>=0;i--)
        {
            if (n[i]<1000) printf("0");
            if (n[i]<100) printf("0");
            if (n[i]<10) printf("0");
            printf("%d",n[i]);
        }
        printf("\n");
    }
    void clear()
    {
        memset(n,0,sizeof(n));
        c=1; n[0]=1;
    }
};
vector <int> vp[4];
point p[11000];
int m,n,k,rp,ri;
void build(int ii)
{
    point pt=p[ii];
    int t,i,j;
    int d[4],o[4];
    d[0]=pt.y; o[0]=0;
    d[1]=n-pt.x+1; o[1]=1;
    d[2]=m-pt.y+1; o[2]=2;
    d[3]=pt.x; o[3]=3;
    for (i=0;i<4-1;i++)
        for (j=i+1;j<4;j++)
        {
            if (d[j]<d[i])
            {
                t=d[i]; d[i]=d[j]; d[j]=t;
                t=o[i]; o[i]=o[j]; o[j]=t;
            }
        }
    (vp[o[0]]).push_back(ii);p[ii].type[o[0]]=true;
    if (d[1]==d[0]) {
        p[ii].type[o[1]]=true; 
        vp[o[1]].push_back(ii);
    }
    if (d[2]==d[0]) {p[ii].type[o[2]]=true; vp[o[2]].push_back(ii);}
    if (d[3]==d[0]) {p[ii].type[o[3]]=true; vp[o[3]].push_back(ii);}
}
int cmp0(const int a,const int b)  //North
{
    point *p1=&p[a];
    point *p2=&p[b];
    int ret=p1->x-p2->x;
    if (ret==0) ret=p1->y-p2->y;
    return ret<0;
}
int cmp1(const int a,const int b)  //East
{
    point *p1=&p[a];
    point *p2=&p[b];
    int ret=p1->y-p2->y;
    if (ret==0) ret=p2->x-p1->x;
    return ret<0;
}
int cmp2(const int a,const int b)  //South
{
    point *p1=&p[a];
    point *p2=&p[b];
    int ret=p1->x-p2->x;
    if (ret==0) ret=p2->y-p1->y;
    return ret<0;
}
int cmp3(const int a,const int b)  //West
{
    point *p1=&p[a];
    point *p2=&p[b];
    int ret=p1->y-p2->y;
    if (ret==0) ret=p1->x-p2->x;
    return ret<0;
}
void output()
{
    int i,j;
    for (i=0;i<4;i++)
    {
        for (j=0;j<(int)vp[i].size();j++)
        {
            p[vp[i][j]].output();
        }
        printf("\n");
    }
}
int main()
{
    bignum ans;
    int x,y,i;
    scanf("%d",&rp);
    for (ri=0;ri<rp;ri++)
    {
        memset(p,0,sizeof(p));
        ans.clear();
        for (i=0;i<4;i++) vp[i].clear();
        point t;
        scanf("%d%d",&n,&m);
        scanf("%d",&k);
        for (i=0;i<k;i++)
        {
            scanf("%d%d",&p[i].x,&p[i].y);
            build(i);
        }
        sort(vp[0].begin(),vp[0].end(),cmp0);
        sort(vp[1].begin(),vp[1].end(),cmp1);
        sort(vp[2].begin(),vp[2].end(),cmp2);
        sort(vp[3].begin(),vp[3].end(),cmp3);
        x=y=0;
        for (i=0;i<(int)vp[0].size();i++)
        {
            point *pt=&p[vp[0][i]];
            if (pt->x>x) x=pt->x; else pt->type[0]=false;
        }
        x=y=0;
        for (i=0;i<(int)vp[1].size();i++)
        {
            point *pt=&p[vp[1][i]];
            if (pt->y>y) y=pt->y; else pt->type[1]=false;
        }
        x=y=0;
        for (i=0;i<(int)vp[2].size();i++)
        {
            point *pt=&p[vp[2][i]];
            if (pt->x>x) x=pt->x; else pt->type[2]=false;
        }
        x=y=0;
        for (i=0;i<(int)vp[3].size();i++)
        {
            point *pt=&p[vp[3][i]];
            if (pt->y>y) y=pt->y; else pt->type[3]=false;
        }
        for (i=0;i<k;i++)
        {
            int j,c=0;
            for (j=0;j<4;j++)
                if (p[i].type[j]) c++;
            if (c==0) break;
            ans.mul(c);
        }
        if (i==k) ans.output(); else printf("0\n");
    }
    return 0;
}

by pxhdg

附加文件