讲道理今天除了第三题秒杀都难想
有 N 个红绿灯的直线道路,给出车通过每个路段需要的时间。每个红绿灯都同步(周期相同且红绿灯状态同时改变),其中绿灯 g 秒,红灯 r 秒。有 Q 辆车在某个时刻从起点出发,问分别会在什么时候到达终点。注意红变绿瞬间可以通过,而绿变红瞬间不可通过。
【输入格式】
输入数据第一行包含三个整数N,g,r,表示红绿灯数量,绿灯持续时间,红灯持续时间。接下来一行 N+1 个整数,依次表示从起点到终点的每个路段所需时间。下一行是一个整数 Q,表示询问次数。后面的 Q 行每行一个询问,询问从 t 时刻出发的公交车会在什么时候到达终点。
【输出格式】
对于每个询问输出到达终点的时间。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110003;
struct tr1 {
tr1* ls;
tr1* rs;
int st;
int lazy;
tr1() {
ls = rs = NULL;
st = lazy = 0;
}
}*root,dizhi[N*60];
int t;
int n;
long long g,r;
long long T[N];
long long f[N];
inline void push_down(tr1* tr) {
if(tr->ls==NULL) tr->ls = &dizhi[++t];
tr->ls->st = tr->lazy;
if(tr->rs==NULL) tr->rs = &dizhi[++t];
tr->rs->st = tr->lazy;
tr->ls->lazy = tr->rs->lazy = tr->lazy;
tr->lazy = 0;
}
void modify(tr1* tr,int l,int r,int x,int y,int z) {
if(l!=r && tr->lazy) push_down(tr);
if(x<=l && r<=y) {
tr->st = z;
tr->lazy = z;
return;
}
int mid = (l+r) >> 1;
if(!(x>mid || y<l)) {
if(tr->ls==NULL) tr->ls = &dizhi[++t];
modify(tr->ls,l,mid,x,y,z);
}
if(!(x>r||y<mid+1)) {
if(tr->rs==NULL) tr->rs = &dizhi[++t];
modify(tr->rs,mid+1,r,x,y,z);
}
}
int query(tr1* tr,int l,int r,int x) {
if(tr->lazy) return tr->lazy;
if(l==r) return tr->st;
int mid = (l+r) >> 1;
if(x<=mid) {
if(tr->ls==NULL) return 0;
else return query(tr->ls,l,mid,x);
} else {
if(tr->rs==NULL) return 0;
else return query(tr->rs,mid+1,r,x);
}
}
long long sf[N];
int main() {
freopen("brt.in","r",stdin);
freopen("brt.out","w",stdout);
scanf("%d%I64d%I64d",&n,&g,&r);
for(int i = 1 ; i <= n+1 ; ++i) scanf("%I64d",&T[i]);
sf[0] = 0;
for(int i = 1 ; i <= n + 1 ; ++i) sf[i] = sf[i-1] + T[i];
f[n] = T[n+1];
root = &dizhi[++t];
for(int i = n-1 ; i >= 0 ; --i) {
int tmp = sf[i+1]%(g+r);
if(tmp<=g) modify(root,0,g+r-1,g-tmp,g+r-tmp-1,i+1);
else {
modify(root,0,g+r-1,0,g+r-tmp-1,i+1);
modify(root,0,g+r-1,g+r-tmp+g,g+r-1,i+1);
}
int arrval_time = (g+r-sf[i]%(g+r))%(g+r);
int tmp2 = query(root,0,g+r-1,arrval_time);
if(tmp2==0) f[i] = sf[n+1]-sf[i];
else {
long long dlt = sf[tmp2]-sf[i];
f[i] = dlt+g+r-dlt%(g+r)+f[tmp2];
}
}
int Q;
scanf("%d",&Q);
while(Q--) {
long long x,ans;
scanf("%I64d",&x);
int tmp2 = query(root,0,g+r-1,x%(g+r));
if(tmp2==0) ans = sf[n+1]+x;
else {
long long dlt = sf[tmp2];
ans = x+dlt+g+r-(x+dlt)%(g+r)+f[tmp2];
}
printf("%I64d\n",ans);
}
}
给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0。
请找到最长的一段连续区间,使得该区间内所有数字之和不超过p。
单调队列优化
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=2*1e6+5;
long long a[maxn],sum[maxn],que[maxn];
long long n,p,d;
int main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
scanf("%I64d%I64d%I64d",&n,&p,&d);
for (int i=1;i<=n;i++)
{
scanf("%I64d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
long long ans=d;
int lf=0;
int head=1;
int tail=0;
for (int rg=d;rg<=n;rg++)
{
while (head<=tail&&sum[rg]-sum[rg-d]>=sum[que[tail]]-sum[que[tail]-d])
tail--;
que[++tail]=rg;
while (sum[rg]-sum[lf]-(sum[que[head]]-sum[que[head]-d])>p)
{
lf++;
if (que[head]-d<lf)
head++;
}
if (rg-lf>ans)
ans=rg-lf;
}
printf("%I64d\n",ans);
return 0;
}
题目描述:
给定一个n*m的矩阵,求最大子矩阵和。
输入:
第一行两个数n,m。
接下来n行每行m个数表示矩阵。
输出:
一行一个数表示最大子矩阵和。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=505;
const int minInf=-1e9;
int jz[maxn][maxn],b[maxn][maxn];
int n,m,ans=minInf;
int main()
{
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&jz[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
b[i][j]=b[i][j-1]+jz[i][j];
for (int i=1;i<=n;i++)
{
for (int j=i;j<=m;j++)
{
int num=0;
for (int k=1;k<=n;k++)
{
if (num>0)
num+=(b[k][j]-b[k][i-1]);
else
num=b[k][j]-b[k][i-1];
if (num>ans)
ans=num;
}
}
}
printf("%d\n",ans);
return 0;
}
维护每一列的前缀和