PAT (Advanced Level) Practice - 1044 Shopping in Mars(25 分)

题目链接:点击打开链接

 

题目大意:找到价值正好等于 m 的子序列下标 “L-R”,若有多个,都输出;若一个也没有,则输出相差最小的(有多个,都输出)。

 

解题思路:差分前缀和 + 二分查找。

 

AC 代码

#include
#include

#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 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;
}

 

你可能感兴趣的:(#,ACM,#,PTA,#,技巧题集,#,查找)