JZOJ5597.红绿灯

原创 2018年04月15日 10:15:37

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;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XLno_name/article/details/79947024

成功软件开发者的9种编程习惯

好的原程序做出好的软件  有些人会想:只要程序运行结果好,就不管原程序编得怎样。但绝对不是这样的。软件不是一次性就作完的,有必要做修改,扩展等管理。所以原程序要尽量作成易看懂,管理方便。  这样做,第...
  • hktl
  • hktl
  • 2001-03-29 01:41:00
  • 791

5597. 红绿灯

题目大意: 你从起点走到终点,中间有很多的红绿灯,遇到红灯不能走,要等到绿灯。红灯和绿灯都是固定的G,R时间。你会从T时刻出发,问到达终点的时间是什么时候。 思路: 这题和2018 GDKO...
  • qq872425710
  • qq872425710
  • 2018-04-15 21:32:20
  • 33

JZOJ 5597 红绿灯

传送门 考场上的思路 正解 参考代码 总结 传送门 考场上的思路   强行模拟;另外 20 分用 DP。结果题意看错了,成功 GG,差点爆零了。   发...
  • lycheng1215
  • lycheng1215
  • 2018-03-24 19:06:10
  • 51

杭电5597

GTW likes function Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Ot...
  • z8110
  • z8110
  • 2015-12-13 14:57:14
  • 181

JZOJ 5609 Tree

传送门 考场上的思路 正解 参考代码(线段树合并) 参考代码(multiset 启发式合并) 传送门 考场上的思路   首先对于前面的小数据可以 O(...
  • lycheng1215
  • lycheng1215
  • 2018-03-28 19:04:12
  • 50

NOIP 2015 Senior 6 - 运输计划

二分答案,树上路径,树上前缀和
  • lycheng1215
  • lycheng1215
  • 2017-09-15 20:37:21
  • 84

模拟赛总结 - 迷之long long

数据类型Orz
  • lycheng1215
  • lycheng1215
  • 2017-07-18 10:27:01
  • 174

排序 - 陪审团

贪心 + 排序
  • lycheng1215
  • lycheng1215
  • 2017-07-10 20:06:16
  • 101

带模板的基于 Treap 的名次树

仅有参考代码
  • lycheng1215
  • lycheng1215
  • 2017-11-25 22:32:42
  • 48

NOIP 2008 Senior 4 - 双栈排序

单栈排序分析,二分图染色,贪心,字典序
  • lycheng1215
  • lycheng1215
  • 2017-10-15 20:30:15
  • 45
收藏助手
不良信息举报
您举报文章:JZOJ5597.红绿灯
举报原因:
原因补充:

(最多只允许输入30个字)