题目链接:点击打开链接
题目大意:找到价值正好等于 m 的子序列下标 “L-R”,若有多个,都输出;若一个也没有,则输出相差最小的(有多个,都输出)。
解题思路:差分前缀和 + 二分查找。
AC 代码
#include<bits/stdc++.h>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof a);
#define INF 0x3f3f3f3f
#define MOD 1000000007
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
ll a[maxn], b[maxn];
unordered_map<ll,int> ump;
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
b[0]=0; ump[0]=-1;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]+=a[i]+b[i-1];
ump[b[i]]=i;
}
// for(int i=0;i<=n;i++) printf("%d ",b[i]); puts("");
int f=1;
for(int i=1;i<=n;i++)
{
ll idx=b[i]-m,l,r=i;
if(idx>=0 && (ump[idx]>0 || ump[idx]==-1)) // 匹配到正好的前缀和
{
f=0;
l=ump[idx]==-1?ump[idx]+2:ump[idx]+1;
printf("%lld-%lld\n",l,r);
}
}
if(f) // 没有匹配到正好的前缀和
{
ll mi=INT_MAX;
for(int i=1;i<=n;i++) // 查找最小值
{
ll idx=b[i]-m,l,r=i;
if(idx<0) continue;
l=upper_bound(b,b+n+1,idx)-b;
mi=min(b[r]-b[l-1],mi);
}
for(int i=1;i<=n;i++) // eq 最小值输出
{
ll idx=b[i]-m,l,r=i;
if(idx<0) continue;
l=upper_bound(b,b+n+1,idx)-b;
if(mi==b[r]-b[l-1])
printf("%lld-%lld\n",l,r);
}
}
}
return 0;
}