7.3总结
7.3总结
得分情况
估分:60+40+100=200
实际:60+40+30=130
Rank 9
萎的一批
好歹把T1T2的暴力分拿满了
T1
比赛的时候想了很久没有思路,就打暴力把人一个个塞进去,拿了暴力分60分
正解:
操作一:
首先,放人进去的时候,优先级是固定的。所以我们可以用后序遍历把优先级搞出来,用一个堆来维护哪些位置是空的,每次放人的时候就从堆里面找一个位置,删人的时候放一个位置进堆里面。(用线段树也可以搞,我就是用线段树打的)
操作二:
我们已经知道哪些点有人,那么把一个人删去时,就用倍增找到他最上面一个有人的节点,把它删去就好了。(用树链剖分也可以搞,cgh打了树剖)
T2
比赛的时候想了很久也没什么思路,就把40分暴力分给拿到了。
正解
首先考虑一种暴力:设f[i][0/1]表示前面的数与i进行位运算,结果的最大值和方案数。这样子做插入是O(\(2^{16}\))的,询问是O(1)的。
怎么平衡一下插入和询问的时间复杂度呢?
运用广义平衡规划的思想,类似折半搜索一样,设f[i][j][0/1]表示前面的数中,前八位为i,与某个后八位为j的数进行位运算,后八位结果的最大值和方案数。
这样一来,插入时i是固定的,我们只用枚举j来更新f;而询问时j是固定的,只用枚举i来更新ans。
好巧妙的思想啊
T3
谴责出题人,暴力随便水过。
我以为它是满足二分性的,结果又TLE有WA爆炸了。
早知道就打暴力算了。
正解
首先,把读入的串分段,同一段里面满足每个数%d都是同一个值
由于不能有重复的数,所以要求一个maright[l]来表示最大右端点使a[l~maright[l]]中没有相同的数。
用哈希或map随便搞搞就好了
然后\(n^2\)暴力就切了哈哈
那么为了避免负数等情况,我们处理一下数据。对于一段每个数a[x],令a[x]=(a[x]-min)/d+1,min即为这一段的最小值。
当l,r为左右端点时,满足\(max\{a_{l...r}\}-min\{a_{l...r}\}+1\leq r-l+1+k\)即可更新答案。
考虑枚举左端点,找最大的右端点
设ma[r]表示当左端点为l时的\(max\{a_{l...r}\}\),mi[r]表示当左端点为l时的\(min\{a_{l...r}\}\)
化一下式子变成\(ma[r]-mi[r]-r\leq k-l\),右边只与l有关。
设\(b[r]=ma[r]-mi[r]-r\),用线段树维护b,那么只用找出最大的r使\(b[r]\leq k-l\)且r<=maright[l]
倒着枚举l,这样每一个ma[r]和mi[r]就只会单调上升或下降。其实ma与mi两个数组本身也是从左到右单调的。
那么当我们把l-1时,从l往后某一段ma就会由 一个小于a[l-1]的数 变为a[l-1]。但是我们不能直接用区间赋值,因为那样的话,由于那一段区间的ma[r]和mi[r]可能不同,所以没法更新区间b[r]的最小值。但是用区间加法就可以了。所以要打两个单调栈维护相同的一块块ma[r]和mi[r]。如果这个区间的ma[r]都相同(其实就等于a[r])且小于a[l],更新标记的时候给这个区间加上a[l]-ma[r];如果这个区间的mi[r](其实就等于a[r])都相同且大于a[l],更新标记的时候给这个区间加上mi[r]-a[l]。//这个地方打反了正负号调了一个小时。
由于线段树里面我们维护的是b[r]的最小值,所以最后用线段树的区间查询找l~n里面最靠右的满足b[r]\(\leq\)k-l并且r<=maright[l]的点就是以l为左端点的答案。
(这几天做过的最难的题目)
(其实也没多难,暴力就切了嘛233)
//for the moon
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 19260817
using namespace std;
struct qy
{
int mi,add;
};
int n,k,d,i,j,st,en,t;
int a[200005],maright[200005];
int ans1,ans2;
int hash[mod+5];
int ma[200005],mi[200005];
int z1[200005],z2[200005];
qy tree[800005];
void pushdown(int k,int l,int r)
{
if (l!=r)
{
tree[k*2].add+=tree[k].add;
tree[k*2+1].add+=tree[k].add;
tree[k*2].mi+=tree[k].add;
tree[k*2+1].mi+=tree[k].add;
}
tree[k].add=0;
}
void update(int k,int l,int r)
{
tree[k].mi=2100000000;
int mid=(l+r)/2;
if (l<=mid) tree[k].mi=min(tree[k].mi,tree[k*2].mi);
if (mid+1<=r)
tree[k].mi=min(tree[k].mi,tree[k*2+1].mi);
}
void insert(int k,int l,int r,int x)
{
pushdown(k,l,r);
if (l==r)
{
tree[k].add=0;
tree[k].mi+=-x;
}
else
{
int mid=(l+r)/2;
if (x<=mid) insert(k*2,l,mid,x);
else insert(k*2+1,mid+1,r,x);
update(k,l,r);
}
}
void add(int k,int l,int r,int x,int y,int z)
{
pushdown(k,l,r);
if ((l<=y)&&(r>=x))
{
if ((l>=x)&&(r<=y))
{
tree[k].add+=z;
tree[k].mi+=z;
return;
}
int mid=(l+r)/2;
add(k*2,l,mid,x,y,z);
add(k*2+1,mid+1,r,x,y,z);
update(k,l,r);
}
}
int query(int k,int l,int r,int x,int y,int z)
{
pushdown(k,l,r);
if ((l<=y)&&(r>=x))
{
int mid=(l+r)/2;
if ((l>=x)&&(r<=y))
{
if (l==r) return l;
else
{
if (tree[k*2+1].mi<=z) return query(k*2+1,mid+1,r,x,y,z);
else return query(k*2,l,mid,x,y,z);
}
}
int tt=0;
if (tree[k*2+1].mi<=z)
tt=query(k*2+1,mid+1,r,x,y,z);
if (tt!=0) return tt;
else return query(k*2,l,mid,x,y,z);
}
else
return 0;
}
void clear(int k,int l,int r)
{
tree[k].mi=tree[k].add=0;
int mid=(l+r)/2;
if (l!=r)
{
clear(k*2,l,mid);
clear(k*2+1,mid+1,r);
}
}
void does(int st,int en)
{
int mii=2000000000;
int l,r,ll,rr;
for (i=st;i<=en;i++)
mii=min(mii,a[i]);
for (i=st;i<=en;i++)
a[i]=(a[i]-mii)/d+1;
z1[0]=z2[0]=0;
for (l=en;l>=st;l--)
{
ma[l]=mi[l]=a[l];
insert(1,st,en,l);
while ((z1[0]>=1)&&(a[z1[z1[0]]]<=a[l]))
{
ll=z1[z1[0]];
rr=z1[z1[0]-1]-1;
if (z1[0]==1) rr=en;
add(1,st,en,ll,rr,a[l]-a[ll]);
z1[0]--;
}
z1[++z1[0]]=l;
while ((z2[0]>=1)&&(a[z2[z2[0]]]>=a[l]))
{
ll=z2[z2[0]];
rr=z2[z2[0]-1]-1;
if (z2[0]==1) rr=en;
add(1,st,en,ll,rr,a[ll]-a[l]);
z2[0]--;
}
z2[++z2[0]]=l;
r=query(1,st,en,l,maright[l],k-l);
if (r-l>=ans2-ans1)
{
ans1=l;
ans2=r;
}
}
clear(1,st,en);
}
int js(long long x)
{
return (long long)x%mod*x%mod;
}
int main()
{
freopen("read.in","r",stdin);
scanf("%d%d%d",&n,&k,&d);
for (i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]=a[i]+1000000000;
}
maright[n]=n;
hash[js(a[n])]=n;
for (i=n-1;i>=1;i--)
{
t=hash[js(a[i])];
maright[i]=maright[i+1];
if (t!=0)
maright[i]=min(t-1,maright[i]);
hash[js(a[i])]=i;
}
st=1;
ans1=ans2=1;
for (i=2;i<=n;i++)
{
if (a[i]%d!=a[i-1]%d)
{
en=i-1;
does(st,en);
st=i;
}
}
does(st,n);
printf("%d %d",ans1,ans2);
return 0;
}