在这里插入代码片
对于初赛爆炸的我只能写这么一道水题来温暖一下心情
原题链接
很显然这是一道大水题,在洛谷上也就是 普 及 − \color{orange}普及- 普及−的难度,由题意不难想到一种 O ( m 3 ) O(m^3) O(m3)(胡乱猜想复杂度)解法:
for(int i=1;i<=m;i++)
{
for(int j=i+1;j<=m;j++)
{
int ans=0;
for(int k=i;k<=j;k++)
{
ans+=k;
}
if(ans==m) cout<<i<<" "<<j<<endl;
}
}
然而这题的数据过于强大,交上去直接
G
G
\color{red}GG
GG
当然这个暴力可以再优化
不难想出,假设区间内就两个数,即
a
a
a和
a
+
1
a+1
a+1,当
a
+
(
a
+
1
)
=
m
a+(a+1)=m
a+(a+1)=m时,即
2
a
+
1
=
m
2a+1=m
2a+1=m,那么无论是
i
i
i还是
j
j
j必定小于
m
2
\frac{m}{2}
2m。
时间复杂度应该是
O
(
(
m
2
)
3
)
O((\frac{m}{2})^3)
O((2m)3)(手胡算的,算错勿喷)
具体
G
G
\color{red}GG
GG没有我也不知道
然后就是继续优化:
在一开始,我们需要先求出全缀和,后面就可以快速求和:
dp[0]=0;
for(int i=1;i<=n;i++)
{
dp[i]=dp[i-1]+a[i];
}
然后就是正经写法:
我们只需要先遍历
l
l
l:
for(int l=1;l<=m/2;l++) //这里l同样取值到m/2
确定
l
l
l之后,既可以二分答案找
r
r
r了。
这里很明显是单调性的,确定
l
l
l的值后,
r
r
r值增大,
l
l
l ~
r
r
r的和也随着增大。
然后就是手胡二分答案:
unsigned long long find(int L,int l,int r)
{
if(l>r) return -1;
int mid=(l+r)>>1;
unsigned long long s=dp[mid]-dp[L-1];
if(s==m)
{
return mid;
}
else
{
if(s>m)
return find(L,l,mid-1);
else return find(L,mid+1,r);
}
}
注意:这里用int会爆炸
然后就写完了 Q w Q QwQ QwQ
(
_____by
l
u
y
i
m
i
n
g
123
\color{orange}luyiming123
luyiming123