URAL_1707

    这个题目一开始感觉好麻烦的,不过多读了几遍之后终于把模型抽象出来了,如果把(si,ti)看成一个点的话,那么后面就是不断地在查询某个矩形范围内是否至少存在一个点,如果该范围内至少存在一个点那么xj就是1,否则xj就是0。

    这让我联想到了POJ_2352数星星那个题,那个题是问一个点(x,y)的左边、下边以及左下方一共有多少个点(后面用sum(x,y)表示这个结果),而我们不难把Ural这个题目化归成那个题,如果矩形左下角是(x1,y1),右上角是(x2,y2)的话,那么最后结果就是sum(x2,y2)+sum(x1-1,y1-1)-sum(x1-1,y2)-sum(x2,y1-1)。

    也就是说我们只要把sum(x,y)都预处理出来就可以搞定这个题目了,而且预处理sum(x,y)的时间复杂度是O(N^2)的,是可以接受的。但是,看了题目中内存的限制心就凉了,如果开二维数组sum[x][y]表示这一结果的话64M是开不下的。

    不过,其实我们只要反问一句真的需要每个(x,y)的sum(x,y)都记录下来吗,问题也就迎刃而解了。因为显然需要保存下来的sum(x,y)个数是依赖于后续查询的次数的,通过计算后发现,后续需要查询的sum(x,y)其实并不多,于是我们就可以用哈希表把需要查询的sum(x,y)的(x,y)先保存下来,然后在预处理的时候遇到需要查询的sum(x,y)的(x,y)时,就将结果再写到哈希表中对应的位置即可。这样后面需要用到时,再直接从哈希中取就行了。

    求解sum(x,y)的过程应该也可以用线段树实现,但我暂时没有实际去敲,因为如果改用线段树去实现统计sum(x,y)这个模块的话,我的程序其他的部分就也要相应的改变不少地方,就等想敲的时候再敲一下吧,先睡觉去了……

    此外,对于q>20的情况需要计算那么一个诡异的表达式的值,由于模的那个数巨大,所以需要用高精度,这样为了节省时间我们可以先把高精度表示的(7^x)%200904040963的结果预处理出来,需要的时候再拿来做加法就可以了。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXN 5010
#define MAXP 570010
#define MAXQ 500010
#define HASH 1000003
const long long int D = 200904040963ll, W = 15;
int N, M, X, P, head[HASH], next[MAXQ], e, A[MAXN];
struct Point
{
    int x, y;
}point[MAXP];
struct Pointnum
{
    int x, y, num;
}pn[MAXQ];
struct Exp
{
    int a0, b0, c0, d0, da, db, dc, dd, q;
}exp[360];
struct BigInteger
{
    int a[W];
    void init(long long int x)
    {
        int i;
        for(i = 0; i < W; i ++)
        {
            a[i] = x % 10;
            x /= 10;
        }
    }
    BigInteger add(BigInteger &b)
    {
        int i;
        long long int s, c;
        BigInteger res;
        c = 0;
        for(i = 0; i < W; i ++)
        {
            s = a[i] + b.a[i] + c;
            res.a[i] = s % 10;
            c = s / 10;
        }
        c = 0;
        for(i = W - 1; i >= 0; i --)
        {
            s = c * 10 + res.a[i];
            c = s % D;
        }
        res.init(c);
        return res;
    }
    BigInteger multiply(int k)
    {
        int i, j;
        long long int s, c;
        BigInteger res;
        c = 0;
        for(i = 0; i < W; i ++)
        {
            s = a[i] * k + c;
            res.a[i] = s % 10;
            c = s / 10;
        }
        c = 0;
        for(i = W - 1; i >= 0; i --)
        {
            s = c * 10 + res.a[i];
            c = s % D;
        }
        res.init(c);
        return res;
    }
    void print()
    {
        int i;
        for(i = W - 1; i > 0; i --)
            if(a[i])
                break;
        for(; i >= 0; i --)
            printf("%d", a[i]);
    }
}seven[360];
int cmpp(const void *_p, const void *_q)
{
    Point *p = (Point *)_p, *q = (Point *)_q;
    if(p->x == q->x)
        return p->y < q->y ? -1 : 1;
    return p->x < q->x ? -1 : 1;
}
void prepare()
{
    int i;
    BigInteger t;
    seven[0].init(1);
    for(i = 1; i < 345; i ++)
        seven[i] = seven[i - 1].multiply(7);
}
void doswap(int &x, int &y)
{
    if(x > y)
    {
        int t;
        t = x, x = y, y = t;
    }
}
void getabcd(int i, int j, int &aj, int &bj, int &cj, int &dj)
{
    aj = ((exp[i].a0 + j * exp[i].da) % N + N) % N;
    bj = ((exp[i].b0 + j * exp[i].db) % N + N) % N;
    cj = ((exp[i].c0 + j * exp[i].dc) % N + N) % N;
    dj = ((exp[i].d0 + j * exp[i].dd) % N + N) % N;
}
int hash(int x, int y)
{
    return (x * N + y) % HASH;
}
void Insert(int x, int y)
{
    if(x < 0 || y < 0)
        return ;
    int i, h = hash(x, y);
    for(i = head[h]; i != -1; i = next[i])
        if(pn[i].x == x && pn[i].y == y)
            break;
    if(i == -1)
    {
        pn[e].x = x, pn[e].y = y;
        next[e] = head[h], head[h] = e;
        ++ e;
    }
}
void init()
{
    int i, j, k, s0, t0, ds, dt, aj, bj, cj, dj;
    X = 0;
    for(i = 0; i < M; i ++)
    {
        scanf("%d%d%d%d%d", &s0, &t0, &ds, &dt, &k);
        for(j = 0; j < k; j ++)
        {
            point[X].x = ((s0 + j * ds) % N + N) % N;
            point[X].y = ((t0 + j * dt) % N + N) % N;
            ++ X;
        }
    }
    qsort(point, X, sizeof(point[0]), cmpp);
    scanf("%d", &P);
    e = 0;
    memset(head, -1, sizeof(head));
    for(i = 0; i < P; i ++)
    {
        scanf("%d%d%d%d%d%d%d%d%d", &exp[i].a0, &exp[i].b0, &exp[i].c0, &exp[i].d0, &exp[i].da, &exp[i].db, &exp[i].dc, &exp[i].dd, &exp[i].q);
        for(j = 0; j < exp[i].q; j ++)
        {
            getabcd(i, j, aj, bj, cj, dj);
            doswap(aj, bj), doswap(cj, dj);
            Insert(bj, dj), Insert(aj - 1, dj), Insert(aj - 1, cj - 1), Insert(bj, cj - 1);
        }
    }
}
void refresh(int x, int y, int num)
{
    int i, h = hash(x, y);
    for(i = head[h]; i != -1; i = next[i])
        if(pn[i].x == x && pn[i].y == y)
            break;
    if(i != -1)
        pn[i].num = num;
}
int getnum(int x, int y)
{
    if(x < 0 || y < 0)
        return 0;
    int i, h = hash(x, y);
    for(i = head[h]; i != -1; i = next[i])
        if(pn[i].x == x && pn[i].y == y)
            break;
    return pn[i].num;
}
void normalquery(int i)
{
    int j, aj, bj, cj, dj;
    for(j = 0; j < exp[i].q; j ++)
    {
        getabcd(i, j, aj, bj, cj, dj);
        doswap(aj, bj), doswap(cj, dj);
        if(getnum(bj, dj) + getnum(aj - 1, cj - 1) - getnum(aj - 1, dj) - getnum(bj, cj - 1) > 0)
            printf("1");
        else
            printf("0");
    }
    printf("\n");
}
void specialquery(int i)
{
    int j, aj, bj, cj, dj;
    BigInteger ans;
    ans.init(0);
    for(j = 0; j < exp[i].q; j ++)
    {
        getabcd(i, j, aj, bj, cj, dj);
        doswap(aj, bj), doswap(cj, dj);
        if(getnum(bj, dj) + getnum(aj - 1, cj - 1) - getnum(aj - 1, dj) - getnum(bj, cj - 1) > 0)
            ans = ans.add(seven[j]);
    }
    ans.print();
    printf("\n");
}
void solve()
{
    int i, j, k, p, cnt, ans;
    memset(A, 0, sizeof(A));
    p = 0;
    for(i = 0; i < N; i ++)
    {
        ans = 0;
        for(j = 0; j < N; j ++)
        {
            cnt = 0;
            while(p < X && point[p].x == i && point[p].y == j)
                ++ p, ++ cnt;
            A[j] += cnt;
            ans += A[j];
            refresh(i, j, ans);
        }
    }
    for(i = 0; i < P; i ++)
    {
        if(exp[i].q <= 20)
            normalquery(i);
        else
            specialquery(i);
    }
}
int main()
{
    prepare();
    while(scanf("%d%d", &N, &M) == 2)
    {
        init();
        solve();
    }
    return 0;
}
posted on 2012-04-12 03:34  Staginner  阅读(424)  评论(0编辑  收藏  举报