51nod 1094 和为k的连续区间(暴力和map优化)

题目意思:

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1094

一整数数列a1, a2, ... , an(有正有负),以及另一个整数k,求一个区间[i, j],(1 <= i <= j <= n),使得a[i] + ... + a[j] = k。

Input

第1行:2个数N,K。N为数列的长度。K为需要求的和。(2 <= N <= 10000,-10^9 <= K <= 10^9)
第2 - N + 1行:A[i](-10^9 <= A[i] <= 10^9)。

Output

如果没有这样的序列输出No Solution。
输出2个数i, j,分别是区间的起始和结束位置。如果存在多个,输出i最小的。如果i相等,输出j最小的。

Input 示例

6 10
1
2
3
4
5
6

Output 示例

1 4

题目分析:

此题很容易就想到暴力的做法,如果没有特殊判题应该也能够AC,这里不在累赘。主要解释map的优化,设计map数据结构mp<__int64,int>,保存s[i](1-i)的和,以及i,就行了,判断的时候,分为两种:一种是s[i]-k==0,肯定满足序列为1~i;第二种:mp[s[i]-k]!!=0证明存在某个s[j],此时洗了为mp[s[i]-k]+1~i。下面给出两种代码

暴力代码O(n*n):

<span style="font-size:18px;">#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<cmath>
using namespace std;
int a[10005];
__int64 s[10005];
int main()
{
    int n; __int64 k;
    while(scanf("%d%I64d",&n,&k)!=EOF){
        memset(s,0,sizeof(s));
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            s[i]=s[i-1]+a[i];
        }
        int ok=1;
        for(int i=1;i<=n;i++){
            for(int j=i;j<=n;j++){
                if(s[j]-s[i-1]==k){
                    printf("%d %d\n",i,j);
                    ok=0;
                    break;
                }
            }
            if(ok==0) break;//退出两层循环
        }
        if(ok) printf("No Solution\n");//没有满足的条件
    }
	return 0;
}</span>

mp优化代码O(n)

<span style="font-size:18px;">#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<cmath>
using namespace std;
int a[10005];
__int64 s[10005];
int main()
{
    int n; __int64 k;
    while(scanf("%d%I64d",&n,&k)!=EOF){
        map<__int64,int> mp;
        memset(s,0,sizeof(s));
        mp[0]=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            s[i]=s[i-1]+a[i];
            mp[s[i]]=i;

        }
        for(int i=n;i>=0;i--){//如果存在相等用前面覆盖后面
            //cout<<s[n-i]<<endl;
            mp[s[i]]=i;
        }
        int ok=1,l,r;
        for(int i=1;i<=n;i++){
            if(s[i]-k==0){//存在
                if(mp[s[i]-k]+1<=i){
                    if(ok){
                        l=mp[s[i]-k]+1; r=i;
                    }
                    else{
                        if(mp[s[i]-k]+1<l) {l=mp[s[i]-k]+1; r=i;}
                        if(mp[s[i]-k]+1==l&&i<r) r=i;
                    }
                    ok=0; //printf("%d %d\n",mp[s[i]-k]+1,i);

                }
            }
            if(mp[s[i]-k]){//存在s[i]-k=s[j]
                if(mp[s[i]-k]+1<=i){
                    if(ok){
                        l=mp[s[i]-k]+1; r=i;
                    }
                    else{
                        if(mp[s[i]-k]+1<l) {l=mp[s[i]-k]+1; r=i;}
                        if(mp[s[i]-k]+1==l&&i<r) r=i;
                    }
                    ok=0; //printf("%d %d\n",mp[s[i]-k]+1,i);
                }
            }

        }
        if(ok) printf("No Solution\n");//没有满足的条件
        else printf("%d %d\n",l,r);
    }
	return 0;
}

</span>
时间: 2024-08-24 15:48:10

51nod 1094 和为k的连续区间(暴力和map优化)的相关文章

51Nod - 1094 和为k的连续区间

51Nod - 1094 和为k的连续区间 一整数数列a1, a2, ... , an(有正有负),以及另一个整数k,求一个区间[i, j],(1 <= i <= j <= n),使得a[i] + ... + a[j] = k. Input 第1行:2个数N,K.N为数列的长度.K为需要求的和.(2 <= N <= 10000,-10^9 <= K <= 10^9) 第2 - N + 1行:A[i](-10^9 <= A[i] <= 10^9). Ou

51nod 1094 和为k的连续区间【前缀和/区间差/map】

1094 和为k的连续区间 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 一整数数列a1, a2, ... , an(有正有负),以及另一个整数k,求一个区间[i, j],(1 <= i <= j <= n),使得a[i] + ... + a[j] = k. Input 第1行:2个数N,K.N为数列的长度.K为需要求的和.(2 <= N <= 10000,-10^9 <= K <= 10^9) 第2 - N 

51Nod 1094 和为k的连续区间 | 水

Input示例 6 10 1 2 3 4 5 6 Output示例 1 4 #include "cstdio" #include "algorithm" #include "iostream" #include "set" using namespace std; #define LL long long #define N 10010 int arr[N]; int main() { int k,n; while(~scan

1094 和为k的连续区间

1094 和为k的连续区间 一整数数列a1, a2, ... , an(有正有负),以及另一个整数k,求一个区间[i, j],(1 <= i <= j <= n),使得a[i] + ... + a[j] = k. Input 第1行:2个数N,K.N为数列的长度.K为需要求的和.(2 <= N <= 10000,-10^9 <= K <= 10^9) 第2 - N + 1行:A[i](-10^9 <= A[i] <= 10^9). Output 如果没

[51nod1094]和为k的连续区间

法一:暴力$O({n^2})$看脸过 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int a[50002],sum[50002]; 5 int main(){ 6 int n,k; 7 cin>>n>>k; 8 for(int i=1;i<=n;i++){ cin>>a[i];sum[i]=sum[i-1]+a[i];} 9 bool flag=f

51nod 1268 和为K的组合

1268 和为K的组合 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 给出N个正整数组成的数组A,求能否从中选出若干个,使他们的和为K.如果可以,输出:"Yes",否则输出"No". Input 第1行:2个数N, K, N为数组的长度, K为需要判断的和(2 <= N <= 20,1 <= K <= 10^9) 第2 - N + 1行:每行1个数,对应数组的元素A[i] (1 <= A[i] &l

poj 1054 The Troublesome Frog (暴力搜索 + 剪枝优化)

题目链接 看到分类里是dp,结果想了半天,也没想出来,搜了一下题解,全是暴力! 不过剪枝很重要,下面我的代码 266ms. 题意: 在一个矩阵方格里面,青蛙在里面跳,但是青蛙每一步都是等长的跳, 从一个边界外,跳到了另一边的边界外,每跳一次对那个点进行标记. 现在给你很多青蛙跳过后的所标记的所有点,那请你从这些点里面找出 一条可能的路径里面出现过的标记点最多. 分析:先排序(目的是方便剪枝,break),然后枚举两个点,这两个 点代表这条路径的起始的两个点.然后是三个剪枝,下面有. 开始遍历时,

[51nod] 1267 4个数和为0 暴力+二分

给出N个整数,你来判断一下是否能够选出4个数,他们的和为0,可以则输出"Yes",否则输出"No". Input 第1行,1个数N,N为数组的长度(4 <= N <= 1000) 第2 - N + 1行:A[i](-10^9 <= A[i] <= 10^9) Output 如果可以选出4个数,使得他们的和为0,则输出"Yes",否则输出"No". Input示例 5 -1 1 -5 2 4 Output

51nod 1001 数组中和等于k的数对(单调性优化)

给出一个整数K和一个无序数组A,A的元素为N个互不相同的整数,找出数组A中所有和等于K的数对.例如K = 8,数组A:{-1,6,5,3,4,2,9,0,8},所有和等于8的数对包括(-1,9),(0,8),(2,6),(3,5). Input 第1行:用空格隔开的2个数,K N,N为A数组的长度.(2 <= N <= 50000,-10^9 <= K <= 10^9) 第2 - N + 1行:A数组的N个元素.(-10^9 <= A[i] <= 10^9)  Outp