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; }