JZOJ5597.红绿灯

Description:

Input:

Output:

Sample Input:

Sample Output:

Data Constraint:

Solution:

30%数据:
按照题意直接模拟即可,设当前走的时间为 x ,若 (x+di) % (g+r)>=g 则在第i个路口遇到红灯。复杂度为 O(nq)

50%数据:
观察题目考虑,在每个路口是否遇到红灯,跟已走时间对 g+r 取模有关。进一步考虑,走的时间取决于开始的时间,所以除去开始时间,每个询问所遇到的红灯,其实跟 g+r 取模后遇到的红灯相同。那么可以解决 g+r 较小的情况,即 g,r<=100 ,对于 g+r 里每一个起始点暴力预处理就好了, O(1) 回答询问,复杂度 O(n(g+r)+q)

100%数据:
既然是否遇到红灯与取模相关,那么我们尝试化出式子:设当前走过时间为 x ,若当前路口遇到红灯,那么就要加上 g+rx % (g+r) ,那么到下一个路口对 g+r 取模的情况就是

(x+g+rxmod(g+r)+di)mod(g+r)

将式子化简可得:
dimod(g+r)

这提醒我们,若遇到了一个红灯,那么它相当于从这个路口第 0 秒开始向终点走去,考虑所有询问遇到了第一个红灯后,都会变成从第 0 秒开始,问题具有了共性,我们可以采取预处理的办法,找到从起点开始遇到的第一个红灯,将该段距离和加上预处理的答案就可以算出来。预处理出一个数组 fi ,表示从第 i 个路口向终点走去需要的时间,这个采取倒推法,具体推法跟处理询问的方式一样: 找到从 i 开始遇到的第一个红灯,由于是第一个红灯,那么在其之前都走过的是绿灯,也就是处理出 di 的前缀和数组 Sumi ,找到一个 j ,使得
(SumjSumi)mod(g+r)[g,g+r)

那么我们采用权值线段树维护每一个前缀和出现的最小路口编号,就可以在权值线段树上查找第一个遇到红灯的路口了,设找到的路口为 k ,则 fi=SumkSumi+fk+g+r(SumkSumi)mod(g+r) 。注意有可能不经过红灯,那么直接取到终点的距离就好。

最后就是询问了:对于询问的处理方式其实类似于 fi 的处理方式,甚至得到答案的式子都跟 fi 的转移类似。只不过将前缀和换成了一个关于初值 ti 的查询,具体不讲了,通过上面的推理,读者应该能够自行解决,那么这题就完美解决了,还要注意一下离散化。复杂度 O((n+q)logn)

Code:

50%数据:

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
ll d[N],ans[N];
ll r,g;
int n,q;
int main()
{
    freopen("light.in","r",stdin);
    freopen("light.out","w",stdout);
    scanf("%d%lld%lld",&n,&g,&r);
    for (int i = 1 ; i <= n + 1 ; ++i) scanf("%lld",d + i);
    scanf("%d",&q);
    if (g <= 100 && r <= 100)
    {
        for (int i = 0 ; i < g + r ; ++i)
        {
            ans[i] = i;
            for (int j = 1 ; j <= n ; ++j)
            {
                ans[i] += d[j];
                if (ans[i] % (g + r) >= g) ans[i] += (g + r) - ans[i] % (g + r);    
            }
            ans[i] += d[n + 1] - i;
        }
        while (q--)
        {
            ll x; scanf("%lld",&x);
            printf("%lld\n",x + ans[x % (g + r)]);
        }
    }else
    {
        while (q--)
        {
            ll x; scanf("%lld",&x);
            for (int i = 1 ; i <= n ; ++i)
            {
                x += d[i];
                if (x % (g + r) >= g) x += (g + r) - x % (g + r);   
            }
            printf("%lld\n",x + d[n + 1]);
        }
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

100%数据:

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
typedef long long ll;
const int N = 5e4 + 5;
const int inf = 0x3f3f3f3f;
int ls[N << 1],rs[N << 1],val[N << 1];
ll d[N],f[N],sum[N],b[N],c[N];
ll g,r;
int n,q,rt,cnt,m;
inline void ins(int &x,int l,int r,int pos,int w)
{
    if (!x) x = ++cnt;
    if (l == r) { val[x] = min(val[x],w); return; }
    int mid = (l + r) >> 1;
    if (pos <= mid) ins(ls[x],l,mid,pos,w);
    else ins(rs[x],mid + 1,r,pos,w);
    val[x] = min(val[ls[x]],val[rs[x]]);
}
inline int qry(int x,int l,int r,int l1,int r1)
{
    if (!x || l1 > r1) return inf;
    if (l >= l1 && r <= r1) return val[x];
    ll mid = (l + r) >> 1; int ret = inf;
    if (l1 <= mid) ret = qry(ls[x],l,mid,l1,r1);
    if (r1 > mid) ret = min(ret,qry(rs[x],mid + 1,r,l1,r1));
    return ret;
}
int main()
{
    freopen("light.in","r",stdin);
    freopen("light.out","w",stdout);
    memset(val,0x3f,sizeof(val));
    scanf("%d%lld%lld",&n,&g,&r);
    for (int i = 1 ; i <= n + 1 ; ++i) scanf("%lld",d + i);
    for (int i = 1 ; i <= n + 1 ; ++i) sum[i] = sum[i - 1] + d[i],c[i] = b[i] = sum[i] % (g + r);
    c[n + 2] = 0,c[n + 3] = g + r;
    sort(c + 1,c + n + 4);
    m = unique(c + 1,c + n + 4) - c - 1;
    for (int i = n ; i >= 1 ; --i)
    {
        int p;
        ll lc = (b[i] + g) % (g + r),rc = (g + r - 1 + b[i]) % (g + r);
        int l1 = lower_bound(c + 1,c + m + 1,lc) - c;
        int r1 = upper_bound(c + 1,c + m + 1,rc) - c - 1;
        if (lc <= rc) p = qry(rt,1,m,l1,r1);
        else p = min(qry(rt,1,m,l1,m),qry(rt,1,m,1,r1));
        if (p < inf) f[i] = sum[p] - sum[i] + g + r - (sum[p] - sum[i]) % (g + r) + f[p];
        else f[i] = sum[n + 1] - sum[i];
        ins(rt,1,m,lower_bound(c + 1,c + m + 1,b[i]) - c,i);
    }
    scanf("%d",&q);
    while (q--)
    {
        ll t,y; int p;
        scanf("%lld",&t); y = (g + r - t % (g + r)) % (g + r);
        ll lc = (y + g) % (g + r),rc = (g + r - 1 + y) % (g + r);
        int l1 = lower_bound(c + 1,c + m + 1,lc) - c;
        int r1 = upper_bound(c + 1,c + m + 1,rc) - c - 1;
        if (lc <= rc) p = qry(rt,1,m,l1,r1);
        else p = min(qry(rt,1,m,l1,m),qry(rt,1,m,1,r1));
        if (p < inf) printf("%lld\n",sum[p] + f[p] + g + r - (sum[p] + t) % (g + r) + t);
        else printf("%lld\n",sum[n + 1] + t);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/XLno_name/article/details/79947024