今天又差点垫底了,下次要加油啊
T1:序列
首先,看到题目所给条件,
a
1
+
⋯
+
a
r
⟩
=
0
\left.\mathrm{a}_{1}+\cdots+\mathrm{a}_{\mathrm{r}}\right\rangle= 0
a1+⋯+ar⟩=0且
b
1
+
⋯
+
b
r
⟩
=
0
\left.b_{1}+\cdots+b_{r}\right\rangle= 0
b1+⋯+br⟩=0,可想到用前缀和记录,即当满足
s
u
m
a
r
−
s
u
m
a
l
−
1
>
=
0
suma_{r}-suma_{l-1}>=0
sumar−sumal−1>=0且
s
u
m
b
r
−
s
u
m
b
l
−
1
>
=
0
sumb_{r}-sumb_{l-1}>=0
sumbr−sumbl−1>=0,此时,题目已转化为一道三维偏序问题,
{
i
≤
j
≤
n
s
u
m
a
i
≤
s
u
m
a
j
s
u
m
b
i
≤
s
u
m
b
j
\left\{\begin{array}{l}{i \leq j \leq n} \\ {suma_{i} \leq suma_{j}} \\ {sumb_{i} \leq sumb_{j}}\end{array}\right.
⎩⎨⎧i≤j≤nsumai≤sumajsumbi≤sumbj
而多维偏序问题,我们多用CDQ分治(我并不会 )或先以
a
a
a为第一关键词,
b
b
b为第二关键词,将
s
u
m
sum
sum数组排序,(记得排序前先离散化),接着以
b
b
b为下标,
i
d
id
id为值,用树状数组维护最小值即可。
代码:
#include<bits/stdc++.h>
#define int long long
#define db double
#define re register
#define cs const
using namespace std;
inline int read()
{
int x=0,f=1;
char ch;
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return f*x;
}
struct node
{
int a,b,num;
}s[1000003];
bool cmp(cs node &x,cs node &y)
{
if(x.a!=y.a) return x.a<y.a;
return x.b<y.b;
}
int n,w[1000003],iii,ans,tree[1000003];
int lowbit(int x)
{
return x&(-x);
}
void update(int i,int x)
{
while(i<=iii)
{
tree[i]=min(tree[i],x);
i+=lowbit(i);
}
}
int query(int x)
{
int ans=0x3f3f3f3f;
while(x)
{
ans=min(ans,tree[x]);
x-=lowbit(x);
}
return ans;
}
signed main()
{
n=read();
memset(tree,0x3f,sizeof(tree));
for(re int i=1;i<=n;++i) s[i].a=read()+s[i-1].a,w[i]=s[i].a;
for(re int i=1;i<=n;++i) s[i].b=read()+s[i-1].b,w[i+n]=s[i].b;
sort(w+1,w+1+2*n);
iii=unique(w+1,w+1+2*n)-w-1;
for(re int i=1;i<=iii;++i)
{
s[i].a=lower_bound(w+1,w+1+iii,s[i].a)-w;
s[i].b=lower_bound(w+1,w+1+iii,s[i].b)-w;
s[i].num=i;
}
sort(s+1,s+1+n,cmp);
for(re int i=1;i<=n;++i)
{
update(s[i].b,s[i].num);
ans=max(ans,s[i].num-query(s[i].b));
}
printf("%d",ans);
}
T2:二叉搜索树
看到这道题,一眼就能看出暴力,而在暴力过程中,我们可以发现这其实是一道区间 D P DP DP,方程为: f l , r = min ( f l , p − 1 + f p + 1 , r + s u m ( l , r ) ) f_{l, r}=\min \left(f_{l, p-1}+f_{p+1, r}+s u m(l, r)\right) fl,r=min(fl,p−1+fp+1,r+sum(l,r))而正常的算法需要 n ³ n³ n³的复杂度,则需要优化,这是区间类(2D1D)动规,我们可以由证明得其决策是具有单调性的,
伪证:设
[
l
,
r
]
[l,r]
[l,r]区间的决策点为p,则
[
l
,
r
+
1
]
[l,r+1]
[l,r+1]区间的决策点会出现在p点右方,而
[
l
−
1
,
r
]
[l-1,r]
[l−1,r]区间的决策点会出现在p点左方,则满足单调性
严谨证明需要用四边形不等式(我不会 )
代码:
#include<bits/stdc++.h>
#define int long long
#define db double
#define re register
#define cs const
using namespace std;
inline int read()
{
int x=0,f=1;
char ch;
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return f*x;
}
int n,f[5005][5005],d[5005][5005],a[5005];
signed main()
{
n=read();
for(re int i=1;i<=n;++i) a[i]=read()+a[i-1],d[i][i]=i,f[i][i]=a[i]-a[i-1];
for(re int len=1;len<=n;++len)
for(re int i=1,j=i+len;j<=n;++i,++j)
{
f[i][j]=1e18;
for(re int k=d[i][j-1];k<=d[i+1][j];++k)
{
if(f[i][k-1]+f[k+1][j]+a[j]-a[i-1]<f[i][j])
{
f[i][j]=f[i][k-1]+f[k+1][j]+a[j]-a[i-1];
d[i][j]=k;
}
}
}
printf("%lld",f[1][n]);
}
T3:走路
咕咕咕!