NOIP2008提高组题解

本文解析了四道编程题目,包括字符串操作、枚举、动态规划及双栈排序等内容,展示了具体的算法思路与代码实现。

T1:笨小猴

考察知识:字符串,素数判定

算法难度:X+ 实现难度:X+

分析:

直接输入后安装要求计算就可以了。

#include<cstdio>
bool isprime(int n){
    if(n<=1) return false;
    for(int i=2;i<n;i++) if(n%i==0) return false;
    return true;
}
int a[28],maxn=0,minn=105;
int main(){
    char s[105];scanf("%s",s);
    for(int i=0;s[i]!='\0';i++) a[s[i]-'a']++;
    for(int i=0;i<26;i++) if(a[i])
        maxn=maxn>a[i]?maxn:a[i],minn=minn>a[i]?a[i]:minn;
    printf("%s\n%d",isprime(maxn-minn)?"Lucky Word":"No Answer",isprime(maxn-minn)?maxn-minn:0);
    return 0;
}

T2:火柴棒等式

考察知识:枚举

算法难度:XX+ 实现难度:XX+

分析:

我们先预处理数字在1...999(因为四位数最少火柴1111,有8根,3个数字就会超过24根)的所有整数需要的火柴棒,然后枚举所有的等式就可以了:

for(i=0;i<=999;i++){
	for(j=0;j<=999;j++){
		if(n==num[i]+num[j]+num[i+j]+4) cnt++;
	}
}

注意到数据范围很小我们可以采取打表法。

代码:

#include<iostream>
using namespace std;
int ans[]={0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,8,9,6,9,29,39,38,65,88,128};
int n;
int main(){
    cin>>n;
    cout<<ans[n]<<'\n';
    return 0;
}

T3:传纸条

考察知识:动态规划

算法难度:XXX+ 实现难度:XXX

分析:

想到方法就不难了,我们可以把两次传纸条看做一次,而这一次没一步有两个位置的变化。

定义状态方程:f(i,j,k)表示两个位置,一个在i,一个在j,且走了k步后得到的最大值

状态转移方程:f(i,j,k)=max\begin{Bmatrix} f(i,j,k-1)\\ f(i-1,j,k-1)\\ f(i,j-1,k-1)\\ f(i-1,j-1,k-1) \end{Bmatrix}+a[i][k-i+2]+a[j][k-j+2]

其中两个位置不能相同

边界:f(1,1,0)=0;

代码:

#include<cstdio>
#define Max(var,var_) var=(var)>(var_)?(var):(var_)
#define F(var,L,R) for(int var=L;var<=R;var++)
int n,m,a[55][55],f[52][52][102];
bool chk(int x,int y,int x_,int y_){
    if(x<1||x>m||y<1||y>n) return false;
    if(x_<1||x_>m||y_<1||y_>n) return false;
    if(x==x_&&y==y_) return false;
    return true;
}
int main(){
    scanf("%d%d",&m,&n);
    F(i,1,m) F(j,1,n) scanf("%d",&a[i][j]);
    F(k,1,m+n-2) F(i,1,m) F(j,1,m) {
        int i_=k+2-i,j_=k+2-j;
        if(i_<1||j_<1||i_>n||j_>n||(i==j&&(i!=m||k!=m+n-2))) continue;
        if(chk(i,i_-1,j,j_-1)) Max(f[i][j][k],f[i][j][k-1]);
        if(chk(i-1,i_,j,j_-1)) Max(f[i][j][k],f[i-1][j][k-1]);
        if(chk(i,i_-1,j-1,j_)) Max(f[i][j][k],f[i][j-1][k-1]);
    	if(chk(i-1,i_,j-1,j_)) Max(f[i][j][k],f[i-1][j-1][k-1]);
    	f[i][j][k]+=a[i][i_]+a[j][j_];
    }
    printf("%d\n",f[m][m][m+n-2]);
    return 0;
}

T4:双栈排序

working...

### 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]. 这种策略利用了三分法的思想,每次都将待测样本缩小三分之一左右的比例,从而提高了效率同时也简化了解决方案的设计难度.
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值