NOIp2017 题解

本文详细介绍了2017年NOIp竞赛中的题目,包括Day1的小凯的疑惑(最短路+记忆化搜索)、时间复杂度(栈模拟)和逛公园(最短路优化),以及Day2的奶酪(并查集/BFS)、宝藏(状压DP)和列队(线段树动态开点)。通过代码解析和问题探讨,帮助理解解题思路和算法应用。

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

Day1

T1 小凯的疑惑

题目传送门

考场上打表搞了一个很奇怪的结论,化简后就是 a ∗ b − a − b a*b-a-b abab。具体证明现在还是不大会。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
LL a,b;
int main(){
    scanf("%lld%lld",&a,&b);
    if (a>b) swap(a,b);
    if (a==1){
        printf("0\n");
        return 0;
    }
    if (a==2){
        printf("%lld\n",b-2);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    LL ans=(4+(a-3)*2+4)*(a-2)/2+1;
    ans+=(b-a-1)*(a-1);
    printf("%lld\n",ans);
    return 0;
}

T2 时间复杂度

题目传送门

一般用一个栈模拟,细节比较多。没什么好说的。

考场上写的代码只会统计第一个循环。。。然而还是有80。

当时太紧张就写得很丑。

代码:

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100
using namespace std;
struct Orz{
    char c;
    bool f;
}stack[MAXN+5];
int top,t,l,cmp,a[MAXN+5],ma;
int f;
char s[MAXN+5],sc[MAXN+5],sx[MAXN+5],sy[MAXN+5];
int main(){
    scanf("%d",&t);
    while (t--){
        memset(a,0,sizeof(a));
        f=0; top=0; cmp=0; ma=0;
        scanf("%d%s",&l,s);
        if (s[2]=='n') f=1;
        for (int i=0;s[i];i++)
            if (s[i]>='0'&&s[i]<='9')
                cmp=cmp*10+s[i]-48;
        int num=0;
        bool flag=false,fa=false,fl=false; if (l&1) flag=true;
        for (int i=1;i<=l;i++){
            int ff=0; char ss[2];
            scanf("%s",ss);
            ff=ss[0];
            if (ff=='F'){
                int c,x=0,y=0;
                scanf("%s%s%s",sc,sx,sy);
                c=sc[0];
                for (int j=0;sx[j];j++)
                    if (sx[j]>='0'&&sx[j]<='9')
                        x=x*10+sx[j]-48;
                for (int j=0;sy[j];j++)
                    if (sy[j]>='0'&&sy[j]<='9')
                        y=y*10+sy[j]-48;
                if (sx[0]=='n') x='n';
                if (sy[0]=='n') y='n';
                if (flag) continue;
                if (a[c-'a']){ flag=true; continue; }
                if (x=='n'&&y!='n') fl=true;
                if (x!='n'&&y!='n'&&x>y) fl=true;
                if (x!='n'&&y=='n') num++;
                if (x!='n'&&y=='n'&&(!fl)) fa=true,ma=max(ma,num);
                a[c-'a']++; 
                Orz p; p.c=c;
                if (x!='n'&&y=='n') p.f=true;
                else p.f=false;
                stack[++top]=p;
            }
            else{
                if (!top) { flag=true; continue; }
                if (stack[top].f) num--;
                a[stack[top--].c-'a']--;
                if (!top) fl=false;
            }
        }
        if (top) flag=true;
        if (flag){
            printf("ERR\n");
            continue;
        }
        if ((fa&&(f==0))||(ma!=cmp&&(f==1))){
            printf("No\n");
            continue;
        }
        printf("Yes\n");
    }
    return 0;
}

T3 逛公园

题目传送门

最短路+记忆化搜索

考场上用最短路优化一下就有60了。。。

先刷一遍反图最短路求出每个点到 n n n的最短路 d i s [ i ] dis[i] dis[i]

f [ i ] [ j ] f[i][j] f[i][j]表示到第 i i i

### NOIP 2017 提高组 初赛题目解析 #### Pascal 编程语言的淘汰时间 关于 Pascal 编程语言何时不再被支持的问题,在选项中给出的时间点为 2022 年[^1]。 #### 归并算法最坏情况下的比较次数 对于两个长度均为 n 的有序数组 A 和 B 进行归并操作时,如果仅考虑元素之间的比较作为基本运算,则在最坏的情况下,至少需要执行 \(2n - 1\) 次比较才能完成整个过程[^2]。 ```python def merge_sorted_arrays(A, B): merged_array = [] i, j = 0, 0 while i < len(A) and j < len(B): if A[i] <= B[j]: merged_array.append(A[i]) i += 1 else: merged_array.append(B[j]) j += 1 # Append any remaining elements from either list merged_array.extend(A[i:]) merged_array.extend(B[j:]) return merged_array ``` 此代码展示了如何有效地将两个已排序列表合并成一个新的已排序列表,并且在这个过程中进行了必要的比较来决定哪个元素应该先加入到新的列表当中去。当处理到最后一个元素的时候,实际上已经完成了 \(2n-1\) 次比较(假设两部分都含有 n 个不同大小的数),这正好对应于上述提到的最佳下界理论值。 #### 硬币分堆与查找不合格品的方法 给定一组数量为 n 枚相同外观但可能有一枚质量不同的硬币组成的集合 A ,通过天平称重的方式找出那枚与众不同的假币: 1. 计算 k 值等于向下取整后的 \(\lfloor{n / 3}\rfloor\); 2. 把这些硬币分为三份 X、Y 和 Z,每一份分别有 k 枚; 3. 如果 X 组和 Y 组的质量不相等的话,那么继续下一步骤;否则跳转至第 5 步; 4. 对较轻的那一侧进一步分割重复以上步骤直到找到唯一可疑对象为止; 5. 当剩下不超过两枚硬币时直接对比即可判断哪一个是异常者;而只有一枚的情况则默认其就是那个特殊个体[^3]. 这种策略利用了三分法的思想,每次都将待测样本缩小三分之一左右的比例,从而提高了效率同时也简化了解决方案的设计难度.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值