蒟蒻打校赛#1

菜鸟菜鸟的编程挑战:算法小能手的成长记
本文记录了一位编程新手在学习过程中,从被队友吊打到逐渐掌握基本算法,如三角形判断、最大公约数计算、高精度运算等,并运用到EasyDP和计算几何问题中的成长历程。通过实例展示了如何用C++解决这些基础问题,最终提升了自己的编程技能。

蒟蒻菜了,被队佬吊打
A.三角形

B. 求gcd

C.a*b

D.isprime
大于3的prime必满足6n+1 or 6n-1 ,从2到判断的 那个数的平方根 逐个判断能否整除那个数。

E.高精度
打不来,
ctrl v了大佬的AC码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int ans,t,pos,n[1005],p[1005];
char N[1005];
int main(){
	scanf("%d\n",&t);
	while(t--){
		for(int i=0;i<=1000;i++)N[i]='*';
		scanf("%s",N);
		int len=0;
		while(N[len]>='0'&&N[len]<='9')len++;
		for(int i=0;i<len;i++)
		  n[i]=N[len-i-1]-'0';
		for(int i=0;i<=1005;i++)
		  p[i]=-1;
		p[0]=1,ans=1,pos=1;
		while(pos){
			for(int i=len-1;i>=0;i--){
				if(n[i]>p[i])break;
				if(n[i]<p[i]){
					pos=0;
					break;
				}
			}
			if(!pos)break;
			ans++;
			int no_=0;
			while(p[no_]>=0){
				p[no_]*=2;
				no_++;
			}
			no_=0;
			while(p[no_]>=0){
				if(p[no_+1]<0&&p[no_]>=10)p[no_+1]=0;
				p[no_+1]+=(p[no_]/10);
				p[no_]%=10;
				no_++;
			}
			if(no_>len)break;
		}
		printf("%d\n",ans-1);
	}
	return 0;
}

F. easy dp
状态转移方程 f[i]=max(f[i-j]-(h[i]-h[i-j]),f[i])(1<=j<=l)
i<l时先处理一下f[i]

#include<bits/stdc++.h>
using namespace std;
int h[100100];
int spent(int x,int y)
{
	if(h[x]>h[y]) return h[x]-h[y];
	else return 0;
}
int main() 
{
    int t;
    int f[100100];
    int n,m,l;
    scanf("%d",&t);
    while(t--)
    {
    	memset(h,0,sizeof(h));
    	memset(f,-1,sizeof(f));
    	scanf("%d%d%d",&n,&m,&l);
    	for(int i=1;i<=n;i++) scanf("%d",&h[i]);
    	f[1]=m;
    	for(int i=2;i<=l;i++)
    	{
    		for(int j=1;j<=i-1;j++)
    		f[i]=max(f[i-j]-spent(i,i-j),f[i]);
		}
		for(int i=l+1;i<=n;i++)
    	{
    		for(int j=1;j<=l;j++)
    		f[i]=max(f[i-j]-spent(i,i-j),f[i]);
		}
		if(f[n]>=0) printf("%d\n",f[n]);
		else printf("-1\n");
	}
	return 0;
}

G.计算几何
如果那个点不在射线的下方,ans=0。
如果在下方,该点必为射线与x轴所截的直线部分的中点。

#include<bits/stdc++.h>
using namespace std;
int main() 
{
    int t;
    int k;
    int x,y;
    double s=0;
    double x1,x2;
    scanf("%d",&t);
    while(t--)
    {
    	x=0.0;
    	x1=(x2=0.0);
        scanf("%d",&k);
    	scanf("%d%d",&x,&y);
    	if(k*x*y==0||y>=k*x) cout<<"0.000"<<endl;
    	else 
    	{
    		x2=(double)(2*y)/k;
    		x1=2*x-x2;
    		s=x1*x2*(double)k/2;
    		printf("%.3f\n",s);
		}
	}
	return 0;
}

未完

<think>嗯,我现在得解决这个凯撒密码的问题,题目是说每个字母向后移动n位,z的下一个是a,循环。那用户给的例子是输入1,qwe变成rxf,看起来每个字母都加1,q变r,w变x,e变f,没问题。那问题就是如何处理循环的情况,比如z移动n位后回到前面。 首先,我得考虑如何将每个字符转换。比如字符是ch,移动n位后的字符应该是怎么计算的。可能的方法是对每个字符,先计算它相对于&#39;a&#39;的位置,然后加上n,再取模26,这样就能保证循环。比如,假设字符是&#39;z&#39;,也就是25的位置,加上n后是25+n,取模26就是(25+n)%26,然后再加上&#39;a&#39;的ASCII值,这样就能得到正确的字符。 比如,当n=1的时候,&#39;z&#39;变成&#39;a&#39;,计算的话就是(25+1)%26=26%26=0,加上97就是97,也就是&#39;a&#39;。这样是对的。 那用户之前提到的那个表达式ch[i]=(ch[i]-&#39;z&#39;)+&#39;a&#39;-1,可能有问题。比如,如果原来的字符加上n之后超过&#39;z&#39;,比如字符是&#39;z&#39;,n=1的话,原字符的ASCII是122,减&#39;z&#39;就是0,然后加&#39;a&#39;-1就是97-1=96,结果就是96,也就是&#39;`&#39;,这显然不对。所以这种方法可能只在n不超过某个范围时有效,但题目中n的范围是1到26,所以当n是26的时候,比如字符是&#39;a&#39;,移动26次应该还是&#39;a&#39;,但用这个方法的话,&#39;a&#39;的ASCII是97,减去&#39;z&#39;(122)得到-25,加上&#39;a&#39;-1也就是96,总和是-25+96=71,对应的是&#39;G&#39;,这明显错误。所以这个表达式有问题,不能正确处理所有情况。 正确的做法应该是,对于每个字符,计算(ch[i] - &#39;a&#39; + n) % 26,然后再加上&#39;a&#39;。这样不管n有多大,都能正确循环。比如,当n=26时,(0 +26)%26=0,加上&#39;a&#39;就是97,即&#39;a&#39;。当n是1的时候,&#39;z&#39;是25,加1得26,模26是0,加上97得&#39;a&#39;,正确。 所以,正确的转换公式应该是:ch[i] = &#39;a&#39; + (ch[i] - &#39;a&#39; + n) % 26。这样不管n是多少,都能正确处理循环。 那现在需要考虑输入的n可能很大,比如超过26,但题目中给出n的范围是1到26,所以可能不需要处理n超过26的情况。不过,即使n超过26,比如n=27,取模26的话是1,所以这个公式依然有效。所以不管n多大,都先取模26可能更安全,但题目里n的范围已经限定了,所以不需要。 现在,编写代码的话,应该读取n和字符串,然后遍历每个字符,应用上述公式。需要注意的是,输入的n可能有多个测试用例,但题目中每个测试用例只处理一次。比如,输入n的值,然后输入字符串,处理每个字符。 举个例子,输入样例中的n=1,字符串是qwe。每个字符处理: q的ASCII是113,减&#39;a&#39;(97)得16,加117,模26还是17,加97得114即r。 w是119-97=22+1=23 → 23+97=120 →x。 e是101-97=4+1=5 →5+97=102→f。所以输出rxf,正确。 那现在代码的大体结构是: 读取n,然后读取字符串,遍历每个字符,转换,然后输出。 在C++中,可以这样做: #include <iostream> #include <string> using namespace std; int main() { int n; string s; cin >> n >> s; // 这里有问题,因为输入格式是第一行n,第二行字符串。所以需要先读n,然后读入第二行,可能中间有换行或者空格。所以正确的方式应该是先读n,然后读入字符串,可能要用getline或者其他方式处理换行。比如,当输入n之后,可能会有换行符残留,导致第二个读取直接得到空字符串。所以需要注意。 比如,正确的输入处理方式可能是: cin >> n; cin.ignore(); // 忽略换行符 getline(cin, s); 或者直接两次cin,比如先读n,然后读入字符串。如果输入中的字符串没有空格的话,cin >> s会正确读取第二行的整个字符串。比如,样例输入: 第一行是1,第二行是qwe,没有空格,所以cin >>n后,再cin >>s,s就是"qwe"。这可能可行。 然后遍历每个字符: for (char &c : s) { c = &#39;a&#39; + (c - &#39;a&#39; + n) % 26; } 然后输出s即可。 测试样例是否正确?比如输入n=1,s=qwe,处理后得到rxf,正确。 那这样的话,代码应该没问题。那用户之前提到的那个错误表达式可能会导致问题,所以正确的公式是这里的这个。那现在需要确保在代码中正确实现这个公式。 那对于n的范围,题目里n是1到26,所以即使n=26,每个字符移动26位,相当于没有移动,所以结果和原字符串相同。例如,字符&#39;a&#39;移动26次后还是&#39;a&#39;。那用这个公式的话,(0 +26)%26=0,加上&#39;a&#39;就是97,正确。 那这样处理是正确的。现在考虑边界情况,比如输入字符是z,n=1,应该变成a。代码中的处理:z是25,加1是26,模26是0,加上97是a,正确。 那代码应该可以正确处理所有情况。因此,这个问题的正确解法应该使用这个转换公式。</think>### 解答思路 凯撒密码的核心是将每个字母循环后移 $n$ 位。关键在于处理 `z` 到 `a` 的循环,需确保字符始终在小写字母范围内(ASCII 码 97~122)。具体步骤如下: 1. **字符位置计算**:将字符转换为相对于 `&#39;a&#39;` 的位置(0~25)。 2. **循环位移**:加上位移量 $n$ 后对 26 取模,确保结果在 0~25 范围内。 3. **还原为字符**:将计算结果转换回 ASCII 字符。 --- ### 代码实现 ```cpp #include <iostream> #include <string> using namespace std; int main() { int n; string s; cin >> n; // 读取位移量n cin >> s; // 读取原文字符串 for (char &c : s) { // 核心公式:循环后移n位 c = &#39;a&#39; + (c - &#39;a&#39; + n) % 26; } cout << s << endl; return 0; } ``` --- ### 关键代码解析 ```cpp c = &#39;a&#39; + (c - &#39;a&#39; + n) % 26; ``` - **`c - &#39;a&#39;`**:将字符转换为 0~25 的数值(例如 `&#39;a&#39;→0`,`&#39;z&#39;→25`)。 - **`+ n`**:执行后移操作。 - **`% 26`**:确保位移后的值在 0~25 范围内,实现循环。 - **`&#39;a&#39; + ...`**:将数值转换回对应的小写字母。 --- ### 示例验证 假设输入为 `n=1`,原文字符串为 `qwe`: 1. `&#39;q&#39;→113`:$113 - 97 = 16$,$16 + 1 = 17$,$17 \% 26 = 17$,$97 + 17 = 114$ → `&#39;r&#39;` 2. `&#39;w&#39;→119`:$119 - 97 = 22$,$22 + 1 = 23$,$23 \% 26 = 23$,$97 + 23 = 120$ → `&#39;x&#39;` 3. `&#39;e&#39;→101`:$101 - 97 = 4$,$4 + 1 = 5$,$5 \% 26 = 5$,$97 + 5 = 102$ → `&#39;f&#39;` 最终输出为 `rxf`,与题目样例一致。 --- ### 复杂度分析 - **时间复杂度**:$O(L)$,其中 $L$ 为字符串长度($L \leq 50$),每个字符仅需常数时间操作。 - **空间复杂度**:$O(1)$,仅需存储输入字符串和少量临时变量。 --- ### 总结 通过数学取模操作,确保所有字符在位移后仍保持在小写字母范围内。该代码能正确处理所有合法输入,包括 `n=26` 的边界情况(此时字符不变化)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值