Luogu P1147连续自然数和 解题报告

在这里插入代码片对于初赛爆炸的我只能写这么一道水题来温暖一下心情

原题链接

很显然这是一道大水题,在洛谷上也就是 普 及 − \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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值