Description:
Input:
Output:
Sample Input:
Sample Output:
Data Constraint:
Solution:
30%数据:
按照题意直接模拟即可,设当前走的时间为
x
,若
50%数据:
观察题目考虑,在每个路口是否遇到红灯,跟已走时间对
g+r
取模有关。进一步考虑,走的时间取决于开始的时间,所以除去开始时间,每个询问所遇到的红灯,其实跟
g+r
取模后遇到的红灯相同。那么可以解决
g+r
较小的情况,即
g,r<=100
,对于
g+r
里每一个起始点暴力预处理就好了,
O(1)
回答询问,复杂度
O(n(g+r)+q)
100%数据:
既然是否遇到红灯与取模相关,那么我们尝试化出式子:设当前走过时间为
x
,若当前路口遇到红灯,那么就要加上
将式子化简可得:
这提醒我们,若遇到了一个红灯,那么它相当于从这个路口第 0 秒开始向终点走去,考虑所有询问遇到了第一个红灯后,都会变成从第
那么我们采用权值线段树维护每一个前缀和出现的最小路口编号,就可以在权值线段树上查找第一个遇到红灯的路口了,设找到的路口为 k ,则
最后就是询问了:对于询问的处理方式其实类似于 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;
}