CSP语法题基础(二)
CSP算法题基础(2)
计算100立方和。立方和公式是平方和公式的平方 k次方公式是k-1次方公式的递推
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int i=1,sum = 0;
while(i <= 100){
sum = sum +i*i*i;
i++;
}
cout<<sum<<endl;
return 0;
}
求斐波那锲数列的第n项:
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int a = 1,b = 1;
int temp;
int num ;
cin >> num;
int i=1;
while( i <= num-1 ){ //注意第一项
temp = a + b;
a = b;
b = temp;
i++;
}
cout<<a<<endl<<b<<endl;
}
do while用的比较少,可能只占5%;而while可以占到95%。功能上来说完全等价。“先上车后买票的思想”
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int s = 0,r = 0;
int i=1,j=1;
while(i<=10){
s = s+i;
i++;
}
cout<<s<<endl;
do{
r = r+j;
j++;
}while(j <=10)
cout<<r<<endl;
return 0;
}
break是直接跳过该循环,并且是全部跳过;
continue是只跳过其中一次循环,继续执行剩下的其他循环
而且二者跳出循环的位置也略有不同:
判断一个数是不是质数。
//对于一个数n,判断2 to n-1里面有没有n的因子
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int n;
cin >> n;
bool is_prime = true;
for(int i = 2;i <= n-1;i++){
if(n%i == 0){
is_prime = false;
break;//break是从for循环里面跳出来
}
}
if(is_prime){
cout<<"是质数"<<endl;
}else{
cout<<"不是质数"<<endl;
}
return 0;
}
计算100以内的偶数
#include<iostream>
#include<cstdio>
using namespace std;
int main() {
int sum = 0;
for(int i=1;i<=100;i++)
{
if(i%2!=1){
sum = sum + i;
}else{
continue;
}
}
cout<<"偶数和是:"<<sum<<endl;
return 0;
}
\(n*n\)矩阵输出
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
// i,j控制在那个位置输出,k负责输出几?
int n;
cin >> n;
int k=1;
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
printf("%-3d",k); //-3意味着后面补上空格
k++;
}
cout<<endl;
}
return 0;
}
输出1-100以内的质数
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
//经典两层循环例子
for(int i=2;i<=100;i++){
bool is_prime = true;
for(int j =2;j<i;j++){
if(i%j==0){
is_prime = false;
break; //判断是否是质数,能够整除的话,跳出本次循环进入输出阶段
}
//break;
}
if(is_prime){ //输出阶段,判断是否是质数,是质数就打印输出
cout<<i<<endl;
}
}
return 0;
}
每一个文件都会有一个文件结束符,但是我们的前端是不会显示的,后端才会有说明EOF或者是-1。cin函数在读入字符的时候会有返回值1,当读到EOF(有的是-1)的时候返回值会是0,所以在acwing721中读到末尾0的时候停止计数,除了可以使用while+if判断结构,还可以直接使用while(cin>>n),无需判断结构。
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int n;
//不知道输入多少个数,用while循环比较好
while(cin >> n){
if(n == 0){
break;
} //输入未知个数 的数,直到是0才停下来
for(int i = 1;i<=n;i++){
cout << i << " ";
}
cout << endl;
}
return 0;
}
类似地,scanf读到EOF返回值是-1,可以有:
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int n;
//不知道输入多少个数,用while循环比较好
while(scanf("%d",&n) != -1){
if(n == 0){
break;
} //输入未知个数 的数,直到是0才停下来
for(int i = 1;i<=n;i++){
cout << i << " ";
}
cout << endl;
}
return 0;
}
10000以内的输入变量cin和scanf效率差不多,但是要是超过10000个输入变量scanf的效率会高很多。
数组
#include<iostream>
using namespace std;
int main(){
int a[3]={1,2,3};
int b[]={4,5,6};
int c[5] = {1,2,3}; //这种情况下,会默认没有定义的变量是0
int d[10] = {0}; //将数组全部初始化成0
return 0;
}
函数里面定义数组的时候,往往是定义到栈空间里;栈空间往往只有1MB,因此定义比较大的数组的时候可能会爆掉;
解决方法:定义到函数外面,因为函数外面定义数组是定义到 堆中,堆空间比较大
同样的一个数组定义到函数(比如main函数)外面,即使不用初始化,会默认是0,从这里看得出定义位置不同,数组会有不同变化。
也就是讲,定义到函数外面的数组甚至不用初始化成0。
局部变量的值是随机的,需要初始化;全局变量的值不需要初始化,默认是0
数组方法求斐波那契数列第n项:
#include<iostream>
using namespace std;
int main(){
int a[100];
int n;
cin >> n;
a[0]=0;
a[1]=1;
for(int i=2;i<=n;i++){
a[i] = a[i-1]+a[i-2];
}
cout<<a[n]<<endl;
return 0;
}
输入数,然后倒叙输出:
#include<iostream>
using namespace std;
int main(){
int a[100];
int n;
cin >> n;
for(int i=0;i<n;i++){
cin >> a[i];
}
for(int j=n-1;j>=0;j--){
cout << a[j]<< " ";
}
return 0;
}
输入n个数,翻转k次:
//使用翻转函数法
include<iostream>
include<algorithm>
using namespace std;
int main(){
int a[100];
int n,k;
cin >> n>>k;
for(int i =0;i<n;i++){
cin >> a[i];
}
reverse(a[0],a[n]);
reverse(a[0],a[k]);
reverse(a[k],a[n]);
for(int j=0;j<n;j++)
cout<<a[i]<" ";
return 0;
}
高精度运算(平时运算属于低精度运算,有效位数比较少)
高精度2的n次幂
数组初始化方式memset函数(在
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int a[10],b[10],c[10];
//使用memset进行初始化,需要注意不是对每一个int初始化,而是对每一个Byte进行初始化
memset(a,0,40); //第一个参数是数组名,第二个参数是需要初始化的内容,第三个参数是从开头到需要初始化的位置,单位是字节
for(int i=0;i<10;i++){
b[i] = i;
}
memcpy(c,b,sizeof c); //把b数组复制到c数组上
memset(a,0,sizeof a)//这里的40也不需要手算,可以用sizeof,这里的sizeof不是函数,而是运算符
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
return 0;
}
字符串之字符数组
#include<iostream>
#include<string.h>
using namespace std;
int main(){
//字符串通常是使用字符数组来进行存储,区别是末尾有'\0'的就是字符串;末尾没有'\0'的是普通的字符数组
char a[]={'c','+','+'}; //就是字符数组
char b[]={'c','+','+','\0'}; //就是字符串
char c[]="c++"; //就是字符串 a字符数组是3个字符;b字符数组是4个字符数组;c字符数组是4个字符数组
//字符串从某一特定字符开始输出,可以使用a+k的格式
cout << b+1 << endl; //就是从+开始输出
printf("%s",c+1);
//输入字符串也可以不从0号元素开始输入
char ss[200];
cin >> ss+1;
cout << ss+1<<endl<<ss[1]<<endl;
//scanf和printf也有类似效果
scanf("%s",ss+1);
printf("%s",ss+1);
//输入输出都是遇到空格、回车、文件结束符才停止
//要想把一行全部读入(包括空格)把包括空格读进来,需要使用fgets(字符数组,最多读入多少字符,stdin) 【把标准读入当做文件】 和getline(), gets()已经被淘汰了
//fgets是把输入读入到字符数组,getline是把输入读入到string里
char ss[200];
/*
cin >> ss+1;
cout << ss+1<<endl<<[ss];
*/
// fgets和getline不能隔离空格和回车,会把按下的回车键也读入到字符数组
fgets(ss,100,stdin);
cout<<ss<<endl;
string s;
getline(cin,s);
cout<<s<<endl;
// 输出一个字符串,还可以使用更简单的puts()函数,自带空格
这三个函数都在#include<string.h>里
//求字符串的长度
strlen(s);
//按照字典序比较字符串的大小,如果是a小于b的话返回-1,如果是a=b的话返回0;如果是a>b的话返回1
strcmp(a,b);
// 将字符串复制给a开始的字符数组
strcpy(a,b);
return 0;
}
刷新缓存(终端特性,终端本身也是函数):其实就是把控制台的输入传输到程序中去,键盘里的输入其实就是,输入字符到键盘缓存,按下回车之后,缓存中的数据就会进入程序之中
字符串之string
可变长字符序列;比字符数组更好用;需要使用库#include
#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
int main(){
//定义方式
string s1; //定义空字符串
string s2 = s1; //不需要strcpy,直接可以赋值过来
string s3 = "ni hao";//s3是该字符串字面值的一个副本
string s4(10,'c'); //定义10个c,内容是:cccccccccc
//读入方式
string s1,s2;
cin >> s1 >> s2;
cout << s1 << " "<< s2<< endl;
// //c++98 不支持这种写法,c++11支持
string s = "Hello World!";
for(char c:s) cout<<c<<endl;
// 若想通过改变c的值来改变s的每一个值,可以在c的前面添加& for(char &c:s) c = 'a';
// 添加一个引用符号,后面在改变c的时候,s也会自动跟着变化
// 引用符号其实起着一个绑定的作用
// auto类型,编译器靠着上下文来 猜 类型,有时候会猜错,c++中有的类型非常长,使用auto会非常长
return 0;
}
字符串流stringstream
stringstream在头文件#include
stringstream ssin(s) //将字符串变成字符串流 的语法。ssin和字符串里面的cin非常相似,不同点是ssin是将字符串流里的读入
用处是可以将字符串变成字符串流,然后从字符串流中提取我们需要的各种信息
比如字符串中 123 yxc 321 1.123就能分别提取出int、string、int、double类型,需要什么信息读取到什么变量中 去
int main(){
string s;
getline(cin,s);
//将字符串初始化成 字符串流
stringstream ssin(s);
int a,b;
string str;
double s;
ssin >> a >> str >> b >> s ;//最好用空格隔开
cout << a << endl << str << endl << b << endl << s << endl;
return 0;
}
给空字符串里面添加字符,可以直接使用 + 符号,
string s;
s = s+'a';//s里面是a
s = s+'b';//s里面是ab
s = s+'c';//s里面是abc
s.pop_back();
PS:Windows下的回车使用的是\r\n(1310),而我们Linux下使用的回车一般是\n(10)
fgets()会把回车读进来,最后一定会补上一个回车
string s;
s.substr(pos,len)//返回的是一个子字符串,位置是pos,长度是len
//要是没有len参数,则默认的是从pos到字符串末尾
要想输出程序运行时间,可以使用#include
这个库中的clock()函数可以返回当前时刻
#include<cmath>
int start_time = clock();
cout << clock - start_time << endl;// 单位是ms
第一种双指针算法
//模式如下
// 最外层一层循环
for(int i =0;i<s.size();i++){
int j =i; //从当前位置开始
while(j<s.size() && s[j] == s[i]) j++; //跳出循环时j已经在不连续相等的第一个字符
i = j-1; //由于最外层循环有i++,所以必须减一,否则会下一轮的起始i会从连续相等的第二个字符开始
}