tc674div1b

题意:给出n个孩子的初始位置,和每个孩子开始的朝向(左或者右),然后孩子的行走规则是,速度始终为1,两人相遇则两人立即转身背向而行。

现在有q次询问,每次问编号为i的孩子在时间t距离原点的距离。返回所有询问之和。

分析:我们现在用另一种方式思考这个行走模式。我们认为,当两个孩子相遇时,他们并没有背向而行,而是交换了身份,并继续保持自己的行进方向和速度。

这样以来,我们就可以认为所有人都始终保持匀速直线运动。每次询问就变成了:设询问编号为i的孩子开始所处的排名(即初始时从左往右数第几个人是他)为x,问现在排名为x的人的坐标。

这个问题可以使用二分查找来解决,用两个数组分别存储向左走的人的坐标和向右走的人的坐标。

每次二分查找这个坐标值。对于一个给定的坐标值我们分别在两个数组中找到它左边有多少人,两组在其左边的人数之和应为排名-1。

当然,在两个数组中数人数的时候有两点需要注意。一个是根据时间平移所有人的坐标。由于坐标是相对的所以不需要平移每个人,只需要反向平移我们枚举的坐标点即可。

二是在数人数的时候仍然要用到二分查找,但是可以直接调用upper_bound进行处理。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>

using namespace std;

const int MOD = (int)(1e9) + 7;
const int MAX_N = (int)(2e5) + 20;

class FindingKids {
public:
    long long getSum(int, int, int, int, int);
};

long long a, b, c;
long long lkid[MAX_N];
long long rkid[MAX_N];
int lcnt, rcnt;
pair<int, int> pos[MAX_N];
int ranks[MAX_N];

void generate(int n)
{
    long long p;
    lcnt = rcnt = 0;
    set<long long> my_set;
    for (int i = 0; i < n; i++)
    {
        a = (a * b % MOD + c) % MOD;
        p = a % (MOD - n + i + 1);
        if (my_set.count(p) > 0)
               p = MOD - n + i;
        my_set.insert(p);
        pos[i] = make_pair(p, i);
        if (p % 2 == 0)
        {
            rkid[rcnt++] = p;
        }else
        {
            lkid[lcnt++] = p;
        }
    }
}

long long work(int id, long long x)
{
    long long l = min(lkid[0] - x, rkid[0] + x);
    long long r = max(lkid[lcnt - 1] - x, rkid[rcnt - 1] + x);
    while (l < r)
    {
        long long mid = l + (r - l) / 2;
        long long lnum = upper_bound(lkid, lkid + lcnt, mid + x) - lkid;
        long long rnum = upper_bound(rkid, rkid + rcnt, mid - x) - rkid;
        if (lnum + rnum < id + 1)
            l = mid + 1;
        else
            r = mid;
    }
    return abs(l);
}

long long FindingKids::getSum(int n, int q, int A, int B, int C) {
    a = A;
    b = B;
    c = C;
    generate(n);
    sort(pos, pos + n);
    for (int i = 0; i < n; i++)
    {
        ranks[pos[i].second] = i;
    }
    sort(lkid, lkid + lcnt);
    sort(rkid, rkid + rcnt);
    long long ret = 0;
    for (int i = 0; i < q; i++)
    {
        a = (a * b % MOD + c) % MOD;
        int kid = ranks[a % n];
        a = (a * b % MOD + c) % MOD;
        long long my_time = a;
        long long temp = work(kid, my_time);
        ret += temp;
    }
    return ret;
}
View Code

 

posted @ 2015-12-14 12:23  金海峰  阅读(201)  评论(0编辑  收藏  举报