PAT-A 1044. Shopping in Mars (25)

本文介绍了一种通过优化枚举求解连续整数序列和的问题,利用前缀和减少计算复杂度,并通过细节调整避免超时。适用于寻找特定和的连续子序列或最接近目标和的子序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接在此

这里在《算法笔记》中归类的二分查找当中,但是目前的题解不是二分法的思路。

题意

给出一个整数n和一个整数pay,然后给出n个整数,在这n个整数中找到所有连续的整数使得这些个连续的整数的和等于pay,如果没有这样的整数序列,则找到大于pay且最接近pay的这样的整数序列。下标从1开始。

思路

暴力枚举求解的方法是最容易想到的,即i从1开始枚举,然后j从1开始枚举。但是这种方法会有三个测试点超时。

后来看了《算法笔记》,里面用的二分的做法,虽然也比较好理解,但是我感觉这种做法虽然有三个测试点超时,但是在细节上修改一下应该能AC,后来在网上找了,也的确看到了相应的题解记录,比如这个

所谓细节上的优化是指:
1. 输入数据的存储上,使用数组保存前i项的和,而不是第i项,即sum[i]=j表示从第1项到第i项的和为j,这样就省去了求前i项和的时间。
2. 当找到了一组序列和大于或等于pay的序列,马上退出j循环,因为下面找到的一定是比这组的序列和要大的序列,不需要继续找下去。
3. 当j循环已经到了n,还没找到符合的条件的序列,则可以跳出所有循环,输出已经保存在ans数组中的信息了。因为j到了n了还没找到符合条件的序列,i++之后的序列和只能更小,也是没有必要再找下去了。

以上就可以通过。不过输入输出需要用printf和scanf,用cin&cout貌似会有一个点超时。

AC代码

#include<cstdio>
#include<cstring>

using namespace std;

int n; 
int pay;
int sum[100010];

int index1 = 0; //控制ans数组的小标,不用index是因为和c++的关键字重复 
int ans[100010][2];  //保存刚好大于pay的序列的下标上下界 
int min = 100000010; 

int main(){

    scanf("%d %d",&n, &pay);
    sum[0] = 0;
    for(int i = 1; i <= n; i++){
        scanf("%d",&sum[i]);
        sum[i] += sum[i-1];
    }

    int i,j ;
    bool flag = false; //用来标记是否有序列和等于pay的序列,有的话flage = true 
    for(i = 1; i <= n; i++) {
        j = i;
        while(j <= n){
            int s = sum[j] - sum[i-1];
            if( s >= pay){ //找到了符合条件的序列 
                if(s == pay){ //序列和等于pay 
                    printf("%d-%d\n",i,j); //直接输出 
                    flag = true; //设置标志位 
                }else{ //s > pay
                    if(s < min){ //如果s比当前序列和最小的那个序列还小 
                        index1 = 0; //,则覆盖掉之前的
                        min = s;
                        ans[index1][0] = i;
                        ans[index1][1] = j;
                        index1++;
                    } else if(s == min){ // s和当前序列和最小的那个序列一样大 
                        min = s;
                        ans[index1][0] = i; //则保存进ans数组 
                        ans[index1][1] = j;
                        index1++;
                    }
                }
                break;
            }
            j++;
        }
        if(j > n) break;
    }

    if(flag == false){ //如果没有序列和等于pay的序列 
        for(int i = 0; i < index1; i++){ //则输出序列和刚好大于pay的序列 
            printf("%d-%d\n",ans[i][0],ans[i][1]);
        }
    }

    return 0;
}

由于s==pay的情况会是s>=pay的情况中最小的那个,所以也可以将两种情况结合起来,写成如下这样。

#include<cstdio>
#include<cstring>

using namespace std;

int n; 
int pay;
int sum[100010];

int index1 = 0; //控制ans数组的小标,不用index是因为和c++的关键字重复 
int ans[100010][2];  //保存刚好大于pay的序列的下标上下界 
int min = 100000010; 

int main(){

    scanf("%d %d",&n, &pay);
    sum[0] = 0;
    for(int i = 1; i <= n; i++){
        scanf("%d",&sum[i]);
        sum[i] += sum[i-1];
    }

    int i,j ;
    for(i = 1; i <= n; i++) {
        j = i;
        while(j <= n){
            int s = sum[j] - sum[i-1];
            if( s >= pay){ //找到了符合条件的序列 
                if(s < min){ //如果s比当前序列和最小的那个序列还小 
                    index1 = 0; //,则覆盖掉之前的
                    min = s;
                    ans[index1][0] = i;
                    ans[index1][1] = j;
                    index1++;
                } else if(s == min){ // s和当前序列和最小的那个序列一样大 
                    min = s;
                    ans[index1][0] = i; //则保存进ans数组 
                    ans[index1][1] = j;
                    index1++;
                }
                break;
            }
            j++;
        }
        if(j > n) break;
    }

    for(int i = 0; i < index1; i++){ //则输出序列和刚好大于pay的序列 
        printf("%d-%d\n",ans[i][0],ans[i][1]);
    }

    return 0;
}

<think>嗯,我现在遇到了Git推送时出现403权限被拒绝的问题,得想办法解决。首先,我记得错误信息大概是说没有权限,可能是公钥的问题或者认证失败。根据用户提供的引用,有几个可能的原因和解决办法。 先看引用[1]和[2],里面提到的是Permission denied (publickey),这通常和SSH密钥有关。用户可能没有正确配置SSH密钥,或者密钥没有被添加到GitHub账户中。解决方法是检查SSH密钥是否存在,生成新的密钥对,然后添加到GitHub的SSH设置里。另外,引用[4]提到要使用默认的id_rsa文件名,可能用户自己修改了密钥文件名导致Git找不到正确的密钥。 然后是引用[3],用户遇到了403错误,使用的是HTTPS协议,这时候可能认证信息有误,或者远程仓库的URL不正确。可能需要检查远程仓库的URL是否属于自己,或者切换成SSH协议来避免认证问题。另外,缓存的身份凭证可能过期或错误,需要清除或者更新。 现在用户的问题可能有两种情况:使用SSH时的公钥问题,或者使用HTTPS时的认证问题。需要分别排查。比如,先检查使用的协议是SSH还是HTTPS,可以通过git remote -v查看远程仓库的URL。如果是HTTPS的URL,可能会因为账号密码错误或者双因素认证的问题导致403。而如果是SSH的URL,则可能是公钥未正确配置。 如果是SSH的问题,步骤应该是生成SSH密钥,添加到ssh-agent,再添加到GitHub账户。如果密钥已经存在,可能需要启动ssh-agent,或者检查权限是否正确,比如密钥文件的权限是否过于开放(应该设置为600)。 如果是HTTPS的问题,可能需要更新凭据,或者检查远程仓库的URL是否正确,是否有权限访问。例如,如果克隆的是别人的仓库,推送时就会没有权限,需要确认仓库归属。另外,使用个人访问令牌(PAT)替代密码也是一个解决办法,因为GitHub已经不再支持密码认证。 还有可能的情况是,用户同时有多个Git账户,导致密钥冲突,这时候需要配置SSH的config文件来指定不同的密钥。 综上,可能的解决步骤包括:确认协议类型,检查密钥配置,更新远程URL为SSH,清除或更新凭据,使用访问令牌,检查仓库权限等。需要一步步排查,根据错误信息的具体情况选择对应的解决方法。</think>### Git推送出现403权限被拒绝的解决方案 #### **1. 检查远程仓库URL类型(SSH/HTTPS)** 首先确认使用的协议类型: ```bash git remote -v ``` - 若URL以`https://`开头,可能出现认证问题;若以`git@github.com:`开头,则属于SSH协议。 - **HTTPS协议问题**:403错误通常与账号权限或缓存凭据有关。 - **SSH协议问题**:需检查SSH密钥配置。 --- #### **2. 针对HTTPS协议的解决方法** ##### (1) 清除缓存凭据 Git会缓存旧密码或令牌,导致认证失败: ```bash git credential-osxkeychain erase host=github.com protocol=https ``` 或手动删除钥匙串中的GitHub条目(Mac)[^3]。 ##### (2) 使用个人访问令牌(PAT)替代密码 GitHub已禁用密码推送,需生成PAT: 1. 进入GitHub **Settings → Developer settings → Personal access tokens**。 2. 生成新令牌(勾选`repo`权限)。 3. 推送时用令牌代替密码输入。 ##### (3) 检查仓库归属权限 若URL指向他人仓库(如`sweetbao/Machine-Reading...`),需修改为你的仓库地址: ```bash git remote set-url origin https://github.com/你的用户名/仓库名.git ``` --- #### **3. 针对SSH协议的解决方法** ##### (1) 生成并添加SSH密钥 ```bash # 生成新密钥(默认路径和文件名) ssh-keygen -t ed25519 -C "your_email@example.com" # 启动ssh-agent并添加密钥 eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519 ``` 将公钥(`~/.ssh/id_ed25519.pub`)粘贴到GitHub **Settings → SSH and GPG keys**[^1][^4]。 ##### (2) 检查SSH连接 ```bash ssh -T git@github.com ``` 若显示`You've successfully authenticated`,则配置成功。 --- #### **4. 其他常见问题** - **密钥权限问题**:确保私钥文件权限为`600`: ```bash chmod 600 ~/.ssh/id_rsa ``` - **多账户冲突**:通过`~/.ssh/config`指定不同仓库的密钥: ``` Host github.com-user1 HostName github.com User git IdentityFile ~/.ssh/user1_key Host github.com-user2 HostName github.com User git IdentityFile ~/.ssh/user2_key ``` 修改仓库URL为对应Host名(如`git@github.com-user1:user1/repo.git`)。 --- #### **总结步骤** 1. 确认URL类型并切换协议(推荐SSH)。 2. 检查密钥配置或生成新密钥。 3. 清除HTTPS缓存凭据或使用PAT。 4. 验证仓库归属权和访问权限。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值