码迷,mamicode.com
首页 > 编程语言 > 详细

ACM学习历程—SNNUOJ 1239 Counting Star Time(树状数组 && 动态规划 && 数论)

时间:2016-05-24 15:13:26      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:

http://219.244.176.199/JudgeOnline/problem.php?id=1239

这是这次陕西省赛的G题,题目大意是一个n*n的点阵,点坐标从(1, 1)(n, n),每个点都有权值,然后从(x, y)x轴的垂线,然后构成一个三角形,三个顶点分别是(0, 0)(x, 0)(x, y)。求三角形内点的权值和,包括边界,n的范围是1000m的范围是100000,说起来也比较坑。。学弟n*m的复杂度竟然水过去了,目测比赛数据比较水。。不过我挂到我们OJ上给了一组随机数据,一组极限数据,然后学弟就T掉了。。(坑学弟系列。。)

不水了,这个题目感觉本身是个很好的题。

刚拿到题,我的第一反应肯定是求出所有的p(x, y),然后往dp的转移方程去考虑。但是发现单纯的递推感觉问题更复杂了。。

但是发现一个重要点就是,斜率小的点,必定被它后面斜率大的点包括。然后,我就想到按x轴枚举每一列,维护每个斜率出现的权值和。那么每一个大的斜率必然是前面枚举过的小的斜率的和,于是便可以树状数组维护了。关键是解决斜率的离散化,我的第一想法是map来进行Hash。当时有了这个思路,本来想着应该可以抢个一血什么的。。结果打到一个小时左右的时候,发现这题已经被好几个人A掉了。。。(什么鬼。。)。我的第一发T了。。通过本地测试,map那个Hash实在太慢了。。于是我开始考虑怎么优化这个Hash,想了好几个办法,要满足y1/x1 < y2/x2,并且Hash(x1, y1) < Hash(x2, y2)的函数实在是没办法。。中间还交了两次错误的Hash方法。。最后队友提醒下,发现那个离散化的过程完全可以一开始预处理,不需要每组数据在线完成,因为数据只有1000*1000,那么所有斜率必然在这个范围内。然后终于A掉了。。

预处理复杂度:O(n*n*log(n*n))

打表:O(n*n*log(n*n))

在线查询:O(m)

最后总的复杂度是O(n*n*log(n*n)+T*(m+n*n*log(n*n)))

如果m大一点的话,这个复杂度还是比较优秀的。。

 

代码:

技术分享
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <string>
#define LL long long

using namespace std;

const int maxM = 1005;
const int maxN = 1000005;
LL d[maxN];

int lowbit(int x)
{
    return x&(-x);
}

void add(int id, int pls)
{
    while(id <= maxN)//id最大是maxN
    {
        d[id] += pls;
        id += lowbit(id);
    }
}

LL sum(int to)
{
    LL s = 0;
    while(to > 0)
    {
        s = s + d[to];
        to -= lowbit(to);
    }
    return s;
}

int gcd(int a, int b)
{
    int r;
    while (b != 0)
    {
        r = b;
        b = a%b;
        a = r;
    }
    return a;
}

struct node
{
    int x, y;

    void create(int xx, int yy)
    {
        int t = gcd(xx, yy);
        x = xx/t;
        y = yy/t;
    }

    bool operator<(node k) const
    {
        return k.x*y < k.y*x;
    }
};

int n, a[maxM][maxM];
LL p[maxM][maxM];
map<node, int> Hash;

void init()
{
    node t;
    for (int i = 1; i < maxM; ++i)
        for (int j = 1; j < maxM; ++j)
        {
            t.create(i, j);
            Hash[t] = 233;
        }
    map<node, int>::iterator it;
    int cnt = 1;
    for (it = Hash.begin(); it != Hash.end(); ++it)
        it->second = cnt++;
}

void input()
{
    memset(d, 0, sizeof(d));
    node t;
    int to;
    scanf("%d", &n);
    for (int i = n; i >= 1; --i)
        for (int j = 1; j <= n; ++j)
            scanf("%d", &a[i][j]);
    for (int j = 1; j <= n; ++j)
    {
        for (int i = 1; i <= n; ++i)
        {
            t.create(j, i);
            to = Hash[t];
            add(to, a[i][j]);
            p[j][i] = sum(to);
        }
    }
}

void work()
{
    int m, u, v;
    scanf("%d", &m);
    for (int i = 1; i <= m; ++i)
    {
        scanf("%d%d", &u, &v);
        printf("%lld\n", p[u][v]);
    }
}

int main()
{
    //freopen("test.in", "r", stdin);
    //freopen("test.out", "w", stdout);
    init();
    int T;
    scanf("%d", &T);
    for (int times = 1; times <= T; ++times)
    {
        printf("Case #%d:\n", times);
        input();
        work();
    }
    return 0;
}
View Code

 

ACM学习历程—SNNUOJ 1239 Counting Star Time(树状数组 && 动态规划 && 数论)

标签:

原文地址:http://www.cnblogs.com/andyqsmart/p/5523288.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!