文章目录

  • C++
  • 1.STL
    • 顺序表的删除(vector, list)
      • vector
      • list
    • {A} + {B} (set)
      • set
    • 统计数字(map)
      • map
    • ACboy 再次需要你的帮助(stack, queue)
      • 容器适配器
    • 栈的操作(stack)
    • 看病要排队(priority_queue)
      • priority_queue
    • 快速排序——中级(sort)
    • 三级排序(sort)
    • 排列(next_permutation)
  • 2.递推算法
    • 菲波那契数列(2)
    • Pell数列
    • 上台阶
    • 爬楼梯
    • 骨牌铺方格——中级
    • 昆虫繁殖
    • 放苹果
    • 移动路线
    • 过河卒
    • 踩方格
    • 位数问题
    • 三角形最佳路径问题
  • 3.递归
    • 汉诺塔问题
    • 求最大公约数问题
    • 后缀表达式的值
  • 4.数论
    • 素数知多少
    • [a,b]区间素数的个数
    • 分解质因子
    • 最大公约数
    • 最小公倍数
    • 青蛙的约会
    • 中国剩余定理
  • 5.分治与二分
    • 查找最接近的元素(二分查找)
    • 取余运算(mod)
    • 简单快速幂

C++

  • 面向对象
  • 万能头文件<bits/stdc++.h>
  • 常用命名空间using namespace std;
  • 输入:cin>>
  • 输出:cout<< ;cout<<endl(换行)

1.STL

顺序表的删除(vector, list)

vector

Description
实现一个线性表:参照sq_delete函数,对一个n不超过2^10的线性表进行删除操作。

Input
第一行有一个整数n,表示线性表的大小,第二行有n个整数,分别是list1,list2…listn。
第三行有一个整数q,表示q次删除操作,接下来q行,每行有一个整数k,表示删除线性表中第k个元素。
(输入有多组测试数据,以EOF结束)

Output
对于每次删除操作输出一行,如果k不合法,输出 -1, 否则输出删除的元素。

Sample Input
5
3 2 1 5 4
3
5
5
2

Sample Output
4
-1
2

#include<bits/stdc++.h>
using namespace std;
int main(){vector<int> ve;int n,i,a,q,k;while(scanf("%d",&n)!=EOF){ //多组测试数据输入ve.clear();for(i=0;i<n;i++){scanf("%d",&a);ve.push_back(a);//在容器的最后添加一个数据 }vector<int>::iterator it;//定义一个迭代器scanf("%d",&q);for(i=0;i<q;i++){scanf("%d",&k);if(k > ve.size()){printf("-1\n");}else{it = ve.begin();for(int j = 0;j < k-1;j++)//指针指向k位置 {it++;}printf("%d\n",*it);ve.erase(it);}}}return 0;
}

list

#include<bits/stdc++.h>
using namespace std;
int main(){int n,k,q,a;list<int> li;while(scanf("%d",&n)!=EOF){li.clear();for(int i=0;i<n;i++){scanf("%d",&a);li.push_back(a);}scanf("%d",&q);list<int>::iterator it;for(int i = 0;i < q;i++){scanf("%d",&k);if(k>li.size())printf("-1\n");else{it=li.begin();for(int j = 0 ;j < k-1;j++){it++;}printf("%d\n",*it);li.erase(it);}}}    return 0;
}

  • 需要高效的随机存取而不再乎中间位置的插入删除->vector
  • 需要大量中间位置的插入删除而不关心随机存取->list
  • 需要随机存取而且关心两端数据的操作->deque

{A} + {B} (set)

set

  • set中的元素已经从小到大排好序,采用平衡树来存储,复杂度logn,其中元素可以是任意类型的。
  • 基本操作:
    begin() 返回指向第一个元素的迭代器
    empty() 如果集合为空,返回true
    erase() 删除集合中的元素
    find() 返回一个指向或查找到元素的迭代器
    lower_bound() 返回指向大于(或等于)某值的第一个元素的迭代器
  • example:
#include<iostream>
#include<set>
using namespace std;
int main(){set<int> s;set<int>::iterator it;  //创建一个对应的迭代器 s.insert(1);s.insert(2);s.insert(3);s.insert(1);cout<<s.count(1)<<endl;cout<<s.count(4)<<endl;it=s.find(2);if(it!=s.end())cout<<*it<<endl;return 0;
}

Description
给你两个集合,要求{A} + {B}.
注:同一个集合中不会有两个相同的元素.

Input
每组输入数据分为三行,第一行有两个数字n,m(0 < n,m <=10000),分别表示集合A和集合B的元素个数.后两行分别表示集合A和集合B.每个元素为不超出int范围的整数,每个元素之间有一个空格隔开.

Output
针对每组数据输出一行数据,表示合并后的集合,要求从小到大输出,每个元素之间有一个空格隔开.

Sample Input
1 2
1
2 3
1 2
1
1 2

Sample Output
1 2 3
1 2

#include<iostream>
#include<set>
using namespace std;
int main(){int n,m,value;set<int> res;set<int>::iterator it;while(cin>>n>>m){res.clear();bool flag=false;for(int i=1;i<=n+m;i++){cin>>value;res.insert(value);}for(it=res.begin();it!=res.end();it++){if(flag)cout<<" "; //除了第一个其他都在输出前输出一个空格 flag=true;cout<<*it;}cout<<endl;} return 0;
}

统计数字(map)

map

记录<key,value>形式元素的容器,元素按key排序
定义map<int ,string>mp;
example:


Description
某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*10^9)。已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。

Input
第1行是整数n,表示自然数的个数。
第2~n+1行每行一个自然数。

Output
包含m行(m为n个自然数中不相同数的个数),按照自然数从小到大的顺序输出。每行输出两个整数,分别是自然数和该数出现的次数,其间用一个空格隔开。

Sample Input
8
2 4 2 4 5 100 2 100

Sample Output
2 3
4 2
5 1
100 2

#include<iostream>
#include<map>
#include<string>
using namespace std;
map<int,int> mp;
map<int,int>::iterator it;
int main(){int n,a,t;while(cin>>n){mp.clear();for(int i=0;i<n;i++){cin>>a;mp[a]++;}for(it=mp.begin();it!=mp.end();it++){cout<<it->first<<" "<<it->second<<endl;}}return 0;
}

ACboy 再次需要你的帮助(stack, queue)

容器适配器

stack<string> s;
stack几个主要函数:
s.empty()堆栈为空则返回真
s.pop()移除栈顶元素(不会返回栈顶元素的值)
s.push(x)在栈顶增加元素
s.size()返回栈中元素数目
s.top()返回栈顶元素

Description
对于每一个样例,第一行是N和一个字符串”FIFO”或者”FILO”(FIFO表示先进先出,即队列;FILO表示先进后出,即栈,),N表示命令的个数,下面有N行,每一行表示一个命令。命令分为两种,IN a 表示进去一个a,OUT表示出一个对头元素或者栈顶元素。

Input
第一行是一个数字T,表示样例的个数,对于每一个样例,如题目所述。

Output
对于每一个OUT命令,你要根据”FIFO”和”FILO”单独一行输出一个数字,或者输出None如果没有整数了。

Sample Input
4
4 FIFO
IN 1
IN 2
OUT
OUT
4 FILO
IN 1
IN 2
OUT
OUT
5 FIFO
IN 1
IN 2
OUT
OUT
OUT
5
FILO
IN 1
IN 2
OUT
IN 3
OUT

Sample Output
1
2
2
1
1
2
None
2
3

#include<bits/stdc++.h>
using namespace std;
int main(){int T,n,m;char c[5],op[5];cin>>T;while(T--){stack<int> s;queue<int> q;cin>>n>>c;if(c[2]=='L'){  for(int i=0;i<n;i++){cin>>op;if(op[0]=='I'){cin>>m;s.push(m);} else if(op[0]=='O'&&!s.empty()){cout<<s.top()<<endl;s.pop();}else cout<<"None"<<endl;}}if(c[2]=='F'){for(int i=0;i<n;i++){cin>>op;if(op[0]=='I'){cin>>m;q.push(m);} else if(op[0]=='O'&&!q.empty()){cout<<q.front()<<endl;q.pop();}else cout<<"None"<<endl;}}}return 0;
}

栈的操作(stack)

Description
栈是一种线性数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
对输入整数序列1 2 3 …执行一组栈操作,输出操作的出栈序列。

Input
每行是一个测试用例,表示一个操作序列。操作序列由P和Q两个符号组成,P表示入栈,Q表示出栈。每个操作序列长度不超过1000。

Output
对每个操作序列,输出出栈序列,若操作序列有错误,如栈空时执行出栈操作,输出error,且终止程序。 出栈序列之间用一个空格隔开,末尾没有多余的空格!

Sample Input
PQPPQQPPPQPQ
PPPPQQP
PP
PQQPP
PPQQ

Sample Output
1 3 2 6 7
4 3
`
1 error
2 1

#include<bits/stdc++.h>
using namespace std;
int main()
{int n,count;string str;stack<int> st;while(cin>>str){n=1;count=str.find_last_of('Q');for(int i=0;i<str.length();i++){if(str[i]=='P'){st.push(n++);}else{if(st.empty()){cout<<"error";break;}else{cout<<st.top();st.pop();}if(i!=count)cout<<" ";}}//重置 while(!st.empty()){st.pop();  }cout<<endl;}return 0;
}

看病要排队(priority_queue)

priority_queue

默认权值最高者排在最前面

Description
看病要排队这个是地球人都知道的常识。
不过经过细心的0068的观察,他发现了医院里排队还是有讲究的。0068所去的医院有三个医生(汗,这么少)同时看病。而看病的人病情有轻重,所以不能根据简单的先来先服务的原则。所以医院对每种病情规定了10种不同的优先级。级别为10的优先权最高,级别为1的优先权最低。医生在看病时,则会在他的队伍里面选择一个优先权最高的人进行诊治。如果遇到两个优先权一样的病人的话,则选择最早来排队的病人。
现在就请你帮助医院模拟这个看病过程。

Input
输入数据包含多组测试,请处理到文件结束。
每组数据第一行有一个正整数N(0 < N < 2000)表示发生事件的数目。
接下来有N行分别表示发生的事件。
一共有两种事件:
1:“IN A B”,表示有一个拥有优先级B的病人要求医生A诊治。(0 2:“OUT A”,表示医生A进行了一次诊治,诊治完毕后,病人出院。(0

Output
对于每个"OUT A"事件,请在一行里面输出被诊治人的编号ID。如果该事件时无病人需要诊治,则输出"EMPTY"。
诊治人的编号ID的定义为:在一组测试中,"IN A B"事件发生第K次时,进来的病人ID即为K。从1开始编号。

Sample Input
7
IN 1 1
IN 1 2
OUT 1
OUT 2
IN 2 1
OUT 2
OUT 1
2
IN 1 1
OUT 1

Sample Output
2
EMPTY
3
1
1

#include<bits/stdc++.h>
using namespace std;
struct Node{int id;int priority;Node(int i,int p){id=i;priority=p;}//通过自定义operator<操作符来比较元素中的优先级bool operator<(const Node &b) const{if(priority==b.priority)return id>b.id; //如果优先级一致,按照先来后到 else return priority < b.priority;  //不然大的优先 }};int main(){int n;while(scanf("%d",&n)!=EOF){priority_queue<Node> pq[4];int t=1;while(n--){string str;int a,b;cin>>str>>a;if(str=="IN"){cin>>b;pq[a].push(Node(t,b));t++;}else if(str=="OUT"){if(pq[a].size()){Node e=pq[a].top();pq[a].pop();cout<<e.id<<endl;}else cout<<"EMPTY"<<endl;}}}return 0;
}

快速排序——中级(sort)

Description
输入n个数,对其进行从小到大排序。

Input
有多组测试数据,每组以n(n<=1000000)开始 第二行开始输入n个整数,整数均可用int类型表示。数据以n=-1结束。

Output
输出每组测试数据组数,排序数据个数以及排序后从小到大的整数序列。最后一个数后没有多于空格。

Sample Input
5
5 4 3 2 1
10
4 6 8 7 5 1 3 9 2 0
-1

Sample Output
Case number:1
Number of elements:5
1 2 3 4 5
Case number:2
Number of elements:10
0 1 2 3 4 5 6 7 8 9

#include<bits/stdc++.h>
using namespace std;
int n,a[1000010];
int t=1;
int main(){while(cin>>n && n!=-1){cout<<"Case number:"<<t<<endl;t++;cout<<"Number of elements:"<<n<<endl;for(int i=0;i<n;i++)cin>>a[i];sort(a,a+n);for(int i=0;i<n-1;i++)cout<<a[i]<<" ";cout<<a[n-1]<<endl;}return 0;
}

三级排序(sort)

Description
给你三维坐标(x, y, z),请给三维坐标排序,优先按x值从小到大排序,当x值一样时,按y值从小到大排序,当y值一样时,按z值从小到大排序。

Input
输入数据的第一行是一个数据T,表示有T组数据。
对于每组数据先输入n (1 < n < 50000),表示有n个三维坐标,然后是n行,每行输入三个整数x, y, z。

Output
对于每组输入数据,先输出n,然后输出n行,为排序后的坐标。

Sample Input
2
2
1 2 3
3 2 1
4
2 3 4
2 2 3
2 3 2
3 4 1

Sample Output
2
1 2 3
3 2 1
4
2 2 3
2 3 2
2 3 4
3 4 1

#include <bits/stdc++.h>
using namespace std;
int n,T;
struct three{int x,y,z;}a[50010];
bool cmp(three x,three y){if(x.x==y.x&&x.y==y.y)return x.z<y.z;if(x.x==y.x)return x.y<y.y;return x.x<y.x;
}int main(){cin>>T;while(T--){cin>>n;cout<<n<<endl;for(int i=0;i<n;i++)cin>>a[i].x>>a[i].y>>a[i].z;sort(a,a+n,cmp);for(int i=0;i<n;i++)cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].z<<endl;}return 0;
}

排列(next_permutation)

Description
1,2,3,…n是自然数1到n的最小的排列,易知,第二小的排列是:1,2,3…n,n-1。现在给你2个值n和m,请找到1到n个数的第m小的排列。

Input
输入包括多组样例,对于每组样例包括两个整数n和m(1<=n<=1000,1<=m<=10000000),分别如题目所述

Output
输出第m小的排列的后各个数字,中间用空格分开,每一个样例占一行

Sample Input
6 4
11 8

Sample Output
1 2 3 5 6 4
1 2 3 4 5 6 7 9 8 11 10

#include <bits/stdc++.h>
using namespace std;
int a[1000010];  //过大的数组要设为全局变量 ,不然栈空间溢出
int main(){int n,m;while(cin>>n>>m){for(int i=0;i<n;i++)a[i]=i+1;for(int i=1;i<m;i++)next_permutation(a,a+n);for(int i=0;i<n-1;i++)printf("%d ",a[i]);printf("%d\n", a[n-1]);}  return 0;
}

2.递推算法

以已知条件,按照递推关系,依次推出中间结果及最后结果。

确定递推变量
|
v
建立递推关系
|
v
确定初始(边界)条件
|
v
由初始条件依据递推公式计算后续状态


菲波那契数列(2)

Description
菲波那契数列是指这样的数列: 数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和。
给出一个正整数a,要求菲波那契数列中第a个数对1000取模的结果是多少。

Input
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数a(1 ≤ a ≤ 1000000)。

Output
n行,每行输出对应一个输入。输出应是一个正整数,为菲波那契数列中第a个数对1000取模得到的结果。

Sample Input
4
5
2
19
1

Sample Output
5
1
181
1

#include<bits/stdc++.h>
using namespace std;
int main(){int a,b,c,m,n;cin>>n;while(n--){a=1;b=1;cin>>m;if(m<3)cout<<1<<endl;else{for(int i=1;i<m-1;i++){c=a+b;a=b;b=c;}cout<<c%1000<<endl;}   }return 0;
}

Pell数列

Description
Pell数列a[1],a[2],a[3], …的定义是这样的,a[1] = 1, a[2] = 2, … , a[n] = 2*a[n−1] + a[n-2] (n>2)。
给出一个正整数k,要求Pell数列的第k项模上32767是多少。

Input
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数k (1≤k<1000000)。

Output
n行,每行输出对应一个输入。输出应是一个非负整数。

Sample Input
2
1
8

Sample Output
1
408

#include<bits/stdc++.h>
using namespace std;
int a[1000];
int main(){int n,c,b,res;cin>>n;for(int i=0;i<n;i++){cin>>a[i];if(a[i]==1 || a[i]==2)cout<<a[i]<<endl;else{c=1;b=2;for(int j=2;j<a[i];j++){res=(c+2*b)%32767;c=b;b=res;}cout<<res<<endl;}}    return 0;
}

上台阶

Description
楼梯有n(71>n>0)阶台阶,上楼时可以一步上1阶,也可以一步上2阶,也可以一步上3阶,编程计算共有多少种不同的走法。

Input
输入的每一行包括一组测试数据,即为台阶数n。最后一行为0,表示测试结束。

Output
每一行输出对应一行输入的结果,即为走法的数目。

Sample Input
1
2
3
4
0

Sample Output
1
2
4
7

#include<bits/stdc++.h>
using namespace std;
long long d[80]={0};
int n;
int main(){d[1]=1;d[2]=2;d[3]=4;for(int i=4;i<=71;i++){d[i]=d[i-1]+d[i-2]+d[i-3];}while(scanf("%d",&n)!=EOF){if(n!=0){cout<<d[n]<<endl;}}return 0;
}

爬楼梯

Description
树老师爬楼梯,他可以每次走1级或者2级,输入楼梯的级数,求不同的走法数。
例如:楼梯一共有3级,他可以每次都走一级,或者第一次走一级,第二次走两级,也可以第一次走两级,第二次走一级,一共3种方法。

Input
输入包含若干行,每行包含一个正整数N,代表楼梯级数,1≤N≤30。

Output
不同的走法数,每一行输入对应一行输出。

Sample Input
5
8
10

Sample Output
8
34
89

#include<bits/stdc++.h>
using namespace std;
int fun(int n){if(n==1)return 1;else if(n==2)return 2;else return fun(n-1)+fun(n-2);
}
int main(){int n;while(scanf("%d",&n)!=EOF){cout<<fun(n)<<endl;}return 0;
}

骨牌铺方格——中级

Description
在2×n的一个长方形方格中,用一个1× 2的骨牌铺满方格,输入n ,输出铺放方案的总数.
例如n=3时,为2× 3方格,骨牌的铺放方案有三种,如下图:

Input
输入数据由多行组成,每行包含一个整数n,表示该测试实例的长方形方格的规格是2×n (0<n<=50)。

Output
对于每个测试实例,请输出铺放方案的总数,每个实例的输出占一行。

Sample Input
1
3
2

Sample Output
1
3
2

数学关系式与上题一样

#include<bits/stdc++.h>
using namespace std;
int fun(int n){if(n==1)return 1;else if(n==2)return 2;else return fun(n-1)+fun(n-2);
}
int main(){int n;while(scanf("%d",&n)!=EOF){cout<<fun(n)<<endl;}return 0;
}

昆虫繁殖

Description
科学家在热带森林中发现了一种特殊的昆虫,这种昆虫的繁殖能力很强。每对成虫过x个月产y对卵,每对卵要过两个月长成成虫。假设每个成虫不死,第一个月只有一对成虫,且卵长成成虫后的第一个月不产卵(过X个月产卵),问过Z个月以后,共有成虫多少对?0≤X≤20,1≤Y≤20,X≤Z≤50。

Input
x,y,z的数值。

Output
过Z个月以后,共有成虫对数。

Sample Input
1 2 8

Sample Output
37

第n月成虫数是上个月成虫数+两个月前的卵,第n月卵数是x月前的成虫数乘以y对。
注意数组要赋初值,默认数组元素是随机数并不是0。

#include<bits/stdc++.h>
using namespace std;
int main(){int x,y,z,a[100]={0},b[100]={0};while(cin>>x>>y>>z){for(int i=1;i<=x;i++){a[i]=1;b[i]=0;}for(int i=x+1;i<=z+1;i++){a[i]=a[i-1]+b[i-2];b[i]=a[i-x]*y;}cout<<a[z+1]<<endl;}return 0;
}

放苹果

Description
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

Input
第一行是测试数据的数目t(0≤t≤20)。以下每行均包含二个整数M和N,以空格分开。1≤M,N≤10。

Output
对输入的每组数据M和N,用一行输出相应的K。

Sample Input
1
7 3

Sample Output
8

#include<bits/stdc++.h>
using namespace std;
int fun(int m,int n){if(n>m)return fun(m,m);else if(m==0)return 1;else if(n==0)return 0;else return fun(m,n-1)+fun(m-n,n);
}
int main(){int m,n,t;cin>>t;while(t--){cin>>m>>n;cout<<fun(m,n)<<endl;}return 0;
}

移动路线

Description
X桌子上有一个m行n列的方格矩阵,将每个方格用坐标表示,行坐标从下到上依次递增,列坐标从左至右依次递增,左下角方格的坐标为(1,1),则右上角方格的坐标为(m,n)。
小明是个调皮的孩子,一天他捉来一只蚂蚁,不小心把蚂蚁的右脚弄伤了,于是蚂蚁只能向上或向右移动。小明把这只蚂蚁放在左下角的方格中,蚂蚁从
左下角的方格中移动到右上角的方格中,每步移动一个方格。蚂蚁始终在方格矩阵内移动,请计算出不同的移动路线的数目。
对于1行1列的方格矩阵,蚂蚁原地移动,移动路线数为1;对于1行2列(或2行1列)的方格矩阵,蚂蚁只需一次向右(或向上)移动,移动路线数也为1……对于一个2行3列的方格矩阵,如下所示:
(2,1) (2,2) (2,3)
(1,1) (1,2) (1,3)
蚂蚁共有3种移动路线:
路线1:(1,1) → (1,2) → (1,3) → (2,3)
路线2:(1,1) → (1,2) → (2,2) → (2,3)
路线3:(1,1) → (2,1) → (2,2) → (2,3)

Input
输入只有一行,包括两个整数m和n(0 < m+n ≤ 20),代表方格矩阵的行数和列数,m、n之间用空格隔开。

Output
输出只有一行,为不同的移动路线的数目。

Sample Input
2 3

Sample Output
3

#include<bits/stdc++.h>
using namespace std;
int main(){int m,n;int dp[20][20];cin>>m>>n;dp[0][0]=1;//一行或一列是都只有一种路线 for(int i=1;i<m;i++){dp[i][0]=1;}for(int i=1;i<n;i++){dp[0][i]=1;}for(int i=1;i<m;i++){for(int j=1;j<n;j++){dp[i][j]=dp[i-1][j]+dp[i][j-1];}}cout<<dp[m-1][n-1]<<endl;;return 0;
}

过河卒

如图,A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。

同时在棋盘上的任一点有一个对方的马(如上图的C点),该马所在的点和所有跳跃一步可达的点称为方马的控制点。例如上图C点上的马可以控制9个点(图中的P1,P2…P8和C)。卒不能通过对方的控制点。
棋盘用坐标表示,A点(0,0)、B点(n, m)(n,m为不超过20的整数,并由键盘输入),同样马 的位置坐标是需要给出的(约定:C≠A,同时C≠B)。现在要求你计算出卒从A点能够到达B点的路径的条数。

Input
B点的坐标(n,m)以及对方马的坐标(X,Y) {不用判错}

Output
一个整数(路径的条数)。

Sample Input
6 6 3 2

Sample Output
17

类似上题,add判断不可走的点就行

#include<bits/stdc++.h>
using namespace std;
long long n,m,x,y,s,dp[20][20];
int main(){cin>>n>>m>>x>>y;dp[0][0]=1;for(int i=1;i<=n;i++){int j=0;//不重合不走马的日 if((i==x&&j==y)||(i==x-1&&j==y-2)||(i==x-1&&j==y+2)||(i==x-2&&j==y-1)||(i==x-2&&j==y+1)||(i==x+1&&j==y-2)||(i==x+1&&j==y+2)||(i==x+2&&j==y-1)||(i==x+2&&j==y+1))continue;dp[i][j]=dp[i-1][j]; } for(int j=1;j<=m;j++){int i=0;if((i==x&&j==y)||(i==x-1&&j==y-2)||(i==x-1&&j==y+2)||(i==x-2&&j==y-1)||(i==x-2&&j==y+1)||(i==x+1&&j==y-2)||(i==x+1&&j==y+2)||(i==x+2&&j==y-1)||(i==x+2&&j==y+1))continue;dp[i][j]=dp[i][j-1];}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if((i==x&&j==y)||(i==x-1&&j==y-2)||(i==x-1&&j==y+2)||(i==x-2&&j==y-1)||(i==x-2&&j==y+1)||(i==x+1&&j==y-2)||(i==x+1&&j==y+2)||(i==x+2&&j==y-1)||(i==x+2&&j==y+1))continue;dp[i][j]=dp[i-1][j]+dp[i][j-1];}}cout<<dp[n][m]<<endl;return 0;
}

踩方格

Description
有一个方格矩阵,矩阵边界在无穷远处。我们做如下假设:
a、每走一步时,只能从当前方格移动一格,走到某个相邻的方格上;
b、走过的格子立即塌陷无法再走第二次;
c、只能向北、东、西三个方向走;
请问:如果允许在方格矩阵上走n步,共有多少种不同的方案。2种走法只要有一步不一样,即被认为是不同的方案。

Input
允许在方格上行走的步数n(n≤20)。

Output
计算出的方案数量。

Sample Input
2

Sample Output
7

对于每个方向,如果向北走则上一步是三个方向的都可以,如果向东(或西)走,则上一步只能是北或东(或西)两个方向来的。

#include<bits/stdc++.h>
using namespace std;
int up[20],le[20],ri[20];
int main(){up[1]=1;le[1]=1;ri[1]=1;int n,res;while(cin>>n){//边界 if(n==1)cout<<3<<endl;else{for(int i=2;i<=n;i++){up[i]=ri[i-1]+le[i-1]+up[i-1];ri[i]=le[i-1]+up[i-1];le[i]=ri[i];}res=up[n]+ri[n]+le[n];cout<<res<<endl; }}return 0;
}

位数问题

Description
在所有的N位数中,有多少个数中有偶数个数字3? 由于结果可能很大,你只需要输出这个答案对12345取余的值。

Input
读入一个数N(N < 1000)。

Output
输出有多少个数中有偶数个数字3。

Sample Input
2

Sample Output
73

#include<bits/stdc++.h>
using namespace std;
const int mod=12345;
int n;
int a[1010][2];
//a[i][0]指i位数中有偶数个3,a[i][1]有奇数个3
int main(){cin>>n;a[1][1]=1;//1-9,3  a[1][0]=8;//1-9,1、2、4、5、6、7、8、9for(int i=2;i<=2;i++){a[i][1]=(a[i-1][0]+a[i-1][1]*9)%mod;a[i][0]=(a[i-1][1]+a[i-1][0]*9)%mod;}cout<<a[n][0]<<endl;return 0;
}

三角形最佳路径问题

Description
如下所示的由正整数数字构成的三角形:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的数字之和。
注意:路径上的每一步只能从一个数走到下一层上和它最近的下边(正下方)的数或者右边(右下方)的数。

Input
第一行为三角形高度100≥h≥1,同时也是最底层边的数字的数目。
从第二行开始,每行为三角形相应行的数字,中间用空格分隔。
1 <= 数 <= 100

Output
最佳路径的长度数值。

Sample Input
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

Sample Output
30

a[i][j]存放从i,j出发到n层的最大值

#include<bits/stdc++.h>
using namespace std;
int a[101][101];
int main(){int n;cin>>n;for(int i=1;i<=n;i++){for(int j=1;j<=i;j++){cin>>a[i][j];}}for(int i=n-1;i>0;i--){for(int j=1;j<=i;j++){if(a[i+1][j]>=a[i+1][j+1])a[i][j]+=a[i+1][j];else a[i][j]+=a[i+1][j+1];}}cout<<a[1][1]<<endl;return 0;
}

3.递归

直接或间接调用自身,用递归将问题分解成规模更小的子问题来解决。

汉诺塔问题

Description
约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到中间的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。
这是一个著名的问题,几乎所有的教材上都有这个问题。由于条件是一次只能移动一个盘,且不允许大盘放在小盘上面,所以64个盘的移动次数是:18,446,744,073,709,551,615
这是一个天文数字,若每一微秒可能计算(并不输出)一次移动,那么也需要几乎一百万年。我们仅能找出问题的解决方法并解决较小N值时的汉诺塔,但很难用计算机解决64层的汉诺塔。
假定圆盘从小到大编号为1, 2, …

Input
输入为一个整数(小于20)后面跟三个单字符字符串。
整数为盘子的数目,后三个字符表示三个杆子的编号。

Output
输出每一步移动盘子的记录。一次移动一行。
每次移动的记录为例如 a->3->b 的形式,即把编号为3的盘子从a杆移至b杆。

Sample Input
2 a b c

Sample Output
a->1->c
a->2->b
c->1->b

总结规律的时候视角放宏观一点

#include<bits/stdc++.h>
#define N 1000010
using namespace std;
void fun(int n,char a,char c,char b)
{if(n==1){printf("%c->%d->%c\n",a,n,b);}else{fun(n-1,a,b,c);  //将n-1个盘子借助b从柱子a移到柱子c上 printf("%c->%d->%c\n",a,n,b);fun(n-1,c,a,b);  //将n-1个盘子借助a从柱子c移到柱子b上}
}
int main()
{int n;char a,b,c;cin>>n>>a>>b>>c;fun(n,a,c,b);return 0;
}

求最大公约数问题

Description
给定两个正整数,求它们的最大公约数。

Input
输入一行,包含两个正整数(<1,000,000,000)。

Output
输出一个正整数,即这两个正整数的最大公约数。

Sample Input
6 9

Sample Output
3

Source
一本通1207

#include<bits/stdc++.h>
using namespace std;
int gcd(int a, int b)//求a与b的最大公约数
{if(a == b)return a;else if(a > b)return gcd(a-b, b);elsereturn gcd(a, b-a);
}
int main()
{int a, b;while(cin >> a >> b){cout << gcd(a, b) << endl;}return 0;
}

后缀表达式的值

Description
从键盘读入一个后缀表达式(字符串),只含有0-9组成的运算数及加(+)、减(—)、乘(*)、除(/)四种运算符。每个运算数之间用一个空格隔开,不需要判断给你的表达式是否合法。以@作为结束标志。

Input
一个后缀表达式。

Output
一个后缀表达式的值。

Sample Input
16 9 4 3 +*-@

Sample Output
-47

#include<bits/stdc++.h>
using namespace std;
long long num[200];
int main(){string str;getline(cin,str);int len = str.length();int n = 0;for(int i = 0;i < len - 1;i++){if(str[i]=='+'){num[n-2]+=num[n-1];n--;}else if(str[i]=='-'){num[n-2]-=num[n-1];n--;}else if(str[i]=='*'){num[n-2]*=num[n-1];n--;}else if(str[i]=='/'){num[n-2]/=num[n-1];n--;}else{long long x=0;while(str[i]!=' '){x=x*10+str[i]-'0';i++;}num[n++]=x;}}cout<<num[0]<<endl;
}

4.数论

素数知多少

Description
在给定区间[1,n]中有多少个素数?

Input
每行一个整数n(1<=n<=1000000)

Output
[1,n]之间素数的个数,独立一行

Sample Input
1013
100

Sample Output
170
25

素数筛的应用
如果2是素数,那么2的所有倍数都是合数,把2所有倍数都标记出来,以此类推

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int prime[N];
bool is_prime[N];
int n;
int fun(){int sum=0;memset(is_prime,true,sizeof(is_prime));is_prime[0]=is_prime[1]=false;for(int i=2;i<=n;i++){if(is_prime[i]){prime[sum++]=i;for(int j=i*2;j<=n;j+=i){is_prime[j]=false;}}}return sum;
}
int main(){while(scanf("%d",&n)!=EOF){cout<<fun()<<endl;}return 0;
}

[a,b]区间素数的个数

Description
给定区间[a,b],你知道其中有多少个素数吗?

Input
每行两个正整数a,b (1<a<=b<1000000)

Output
[a,b]之间素数的个数

Sample Input
1 11
11 11111

Sample Output
5
1341

#include <bits/stdc++.h>
using namespace std;
int n;
bool fun(int x);
int main(){int a,b,sum;while(scanf("%d%d",&a,&b)!=EOF){sum=0;for(int i=a;i <= b;i++){if(fun(i)==true)sum++;}cout<<sum<<endl;}    return 0;
}
bool fun(int x){if(x<2)return false;for(int i = 2;i <= x/i;i++)if(x%i==0)return false;return true;
}

分解质因子

Description
在数论里,某一正整数的质因子指能整除该数的质数整数。比如12的质因子有2和3。给定一个正整数n,你知道它的质因子有哪些吗?

Input
每行一个正整数n (1<n<1000000)

Output
n的质因子,从小到大,任意两个之间用一个空格隔开,独立一行

Sample Input
12
210

Sample Output
2 3
2 3 5 7

#include <bits/stdc++.h>
using namespace std;void divide(int n){for(int i=2;i<=n/i;i++){if(n%i==0){while(n%i==0)n/=i;cout<<i<<' ';}}if(n>1)cout<<n;
}
int main(){int n;while(scanf("%d",&n)!=EOF){divide(n);cout<<endl;}return 0;
}

最大公约数

Description
公约数,亦称“公因数”。它是几个整数同时均能整除的整数。如果一个整数同时是几个整数的约数,称这个整数为它们的“公约数”;公约数中最大的称为最大公约数。两个数a,b的最大公约数记为gcd(a,b)。给定任意两个正整数a,b,你知道gcd(a,b)是多少吗?

Input
每行两个正整数a,b

Output
gcd(a,b),独立一行

Sample Input
5 6
20 12

Sample Output
1
4

欧几里得算法

#include <bits/stdc++.h>
using namespace std;
int gcd(int a,int b){if(a%b==0)return b;elsereturn gcd(b,a%b);
}
int main(){int a,b,c;if(a<b){c=a;a=b;b=c;}while(scanf("%d%d",&a,&b)!=EOF){cout<<gcd(a,b)<<endl;}return 0;
}

最小公倍数

Description
最小公倍数(Least Common Multiple,缩写L.C.M.),如果有一个自然数a能被自然数b整除,则称a为b的倍数,b为a的约数,对于两个整数a,b来说,指该两数共有倍数中最小的一个,记为lcm(a,b)。

Input
每行两个正整数a,b

Output
lcm(a,b),独立一行

Sample Input
5 6
1 19

Sample Output
30
19

#include <bits/stdc++.h>
using namespace std;
//两个数的乘积会很大,超过int的表示范围
long long gcd(int a,int b){if(a%b==0)return b;else return gcd(b,a%b);
}
int main(){int a,b;while(cin>>a>>b){cout<<a/gcd(a,b)*b<<endl; }return 0;
}

青蛙的约会

Description
两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。
我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。

Input
输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。

Output
输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"Impossible"

Sample Input
1 2 3 4 5

Sample Output
4

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll x,y,m,n,l;
void ex_gcd(ll a,ll b,ll &x,ll &y,ll &d){if(!b){d=a;x=1;y=0;return ;}ex_gcd(b,a%b,y,x,d);y-=x*(a/b);
}
int main(){while(cin>>x>>y>>m>>n>>l){ll dx,dy,gcd;ex_gcd(n-m,l,dx,dy,gcd);if((x-y)%gcd)cout<<"Impossible"<<endl;else{ll t=l/gcd;dx=(x-y)/gcd*dx;cout<<(dx%t+t)%t<<endl;}}return 0;
}

中国剩余定理

Sample Input
3
2 3 2
3 5 7

Sample Output
23

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ex_gcd(ll a,ll b,ll &x,ll &y){if(b==0){x=1;y=0;return a;}ll ans = ex_gcd(b,a%b,x,y);ll tmp=x;x=y;y=tmp-a/b*y;return ans;
}
ll crt(ll a[],ll m[],ll n){ll M=1;ll ans=0;for(ll i=0;i<n;i++)M*=m[i];for(int i=0;i<n;i++){ll x,y;ll Mi=M/m[i];ex_gcd(Mi,m[i],x,y);ans=(ans+a[i]*Mi*x)%M;} if(ans<0)ans+=M;return ans;
}
int main(){ll n,b[10],w[10];while(cin>>n){for(int i=0;i<n;i++)cin>>b[i];for(int i=0;i<n;i++)cin>>w[i];cout<<crt(b,w,n)<<endl;}return 0;
}

5.分治与二分

查找最接近的元素(二分查找)

Description
在一个非降序列中,查找与给定值最接近的元素。

Input
第一行包含一个整数n,为非降序列长度。1 ≤ n ≤ 100000。
第二行包含n个整数,为非降序列各元素。所有元素的大小均在0-1,000,000,000之间。
第三行包含一个整数m,为要询问的给定值个数。1 ≤ m ≤ 10000。
接下来m行,每行一个整数,为要询问最接近元素的给定值。所有给定值的大小均在0-1,000,000,000之间。

Output
m行,每行一个整数,为最接近相应给定值的元素值,保持输入顺序。若有多个值满足条件,输出最小的一个。

Sample Input
3
2 5 8
2
10
5

Sample Output
8
5

#include<bits/stdc++.h>
using namespace std;
#define Max 1000000
int a[Max];
int main(){int n,m,x,low,high;cin>>n;for(int i=1;i<=n;i++){cin>>a[i];}cin>>m;while(m--){cin>>x;low=1,high=n;//low<high将会死循环 while(low<high-1) {int mid=(low+high)/2;if(a[mid]>x)high=mid;else low=mid;} if(fabs(a[low]-x)>fabs(a[high]-x))cout<<a[high]<<endl;else cout<<a[low]<<endl;}return 0;
}

取余运算(mod)

Description
输入b,p,k的值,求b^p mod k的值。其中b,p,k为长整型数。

Input
输入b,p,k的值。

Output
求b^p mod k的值。

Sample Input
2 10 9

Sample Output
2^10 mod 9=7

#include<bits/stdc++.h>
using namespace std;
typedef long long int LLI;
LLI fun(LLI b,LLI p,LLI k){LLI res;if(p==0)return 1;res=fun(b,p/2,k)%k;res=res*res%k;if(p%2==1)res=res*b%k;return res;
}
int main(){LLI b,p,k;cin>>b>>p>>k;b%=k;cout<<b<<"^"<<p<<" "<<"mod"<<" "<<k<<"="<<fun(b,p,k)<<endl;return 0;
}

简单快速幂

Description
杰哥又遇到难题了,大家快来帮他解决。
这次题目很简单。给你一个整数N,求NN的个位数。
当然,事实上作为学霸,杰哥才不会问如此简单的问题呢。注意这里的N非常大:N(1<=N<=1,000,000,000)。

Input
第一行包含一个正整数T,代表有多少组测试样例。
接下T行中每行有一个正整数N

Output
对于每一组测试样例,输出NN的个位数。

Sample Input
2
3
4

Sample Output
7
6

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL fun(LL a,LL b){LL res=1;while(b!=0){if(b%2==1)res=res*a;a=a*a;b/=2;   }return res;
}
int main(){LL N,T,ans;cin>>T;while(T--){cin>>N;ans=fun(N,N)%10;cout<<ans<<endl;}return 0;
}

中学信息奥赛course相关推荐

  1. 大连计算机学校贾佳,大连市第二十四中学信息学奥赛喜报频传

    大连市第二十四中学信息学奥赛喜报频传 大连市第二十四中学竞赛部崔殿宝张新钢 由中国计算机学会(CCF)主办的国际信息学奥林匹克竞赛(IOI2018)中国队选拔赛暨精英赛(以下简称CCF CTSC)于5 ...

  2. 数学奥赛VS信息奥赛 | 为孩子选择更好地升学之路!

    随着社会的不断发展,在孩子成长学习中,家长越来越注重孩子的全面发展.从小学就开始为孩子规划竞赛学习,也是很多家长的选择,因为在学习的同时,也可以为以后高考自主招生提前做准备. 但是现在各种类目的竞赛, ...

  3. 信息奥赛一本通的递推练习

    信息奥赛一本通的递推练习 递推与动态规划 1313:位数问题 1314:过河卒 1194:移动路线 1196:踩方格 递推与动态规划 递推解决的问题中满足最优化原理的也是属于动态规划范畴 1313:位 ...

  4. 美国计算机科学奥林匹克竞赛试题,中学信息奥林匹克竞赛试题精选.doc

    中学信息奥林匹克竞赛试题精选 第十届提高组奥林匹克竞赛试题一 一. 单项选择题(共10题,每题1.5分,共计15分.每题有且仅有一个正确答案.). ?1.???????? 设全集I = {a, b, ...

  5. 江苏省盐城中学信息竞赛队(YZOI)队规

    江苏省盐城中学信息竞赛队规江苏省盐城中学信息竞赛队规江苏省盐城中学信息竞赛队规 1.竞赛队队员需注册CSDN账号并私信教练(CSDN账号:以太以北).队长(CSDN账号:珂学的小萌新)关注. 2.每学 ...

  6. 数论 初等数论 北师大 张秀平 自学 学习 经验 视频 信息 奥赛 NOIP

    姐妹篇详见https://blog.csdn.net/mrcrack/article/details/87897210 数论 初等数论 北师大 张秀平 自学 学习 经验 视频 信息 奥赛 NOIP 初 ...

  7. 【算法•日更•第十二期】信息奥赛一本通1585:【例 1】Amount of Degrees题解

    废话不多说,直接上题: 1585: [例 1]Amount of Degrees 时间限制: 1000 ms         内存限制: 524288 KB 提交数: 130     通过数: 68 ...

  8. 信息奥赛一本通 三角形最佳路径问题 (1288) 题解

    信息奥赛一本通 三角形最佳路径问题 (1288) 题解 时间限制: 1000 ms 内存限制: 65536 KB 题目描述 如下所示的由正整数数字构成的三角形: 7 3 8 8 1 0 2 7 4 4 ...

  9. 高中生计算机竞赛取消了么,有了强基计划,你还会让孩子参加信息奥赛吗?

    中国计算机学会秘书长杜子德在接受记者采访时表示:教育部官宣取消"自主招生".推出"强基计划"这对信息学奥赛是利好,能够让NOI回归其本质和属性,让希望通过参加N ...

最新文章

  1. CSS中的颜色和字体
  2. 内网渗透测试:隐藏通讯隧道技术(上)
  3. python udp client
  4. 计算机的诊断策略服务怎么打开,win7系统使用诊断策略服务提示“未运行”怎么解决...
  5. 十、从中缀向后缀转换表达式
  6. python学习笔记(四)字典(dict)
  7. 他的前端焦虑:30岁以后的前端路怎么走? 你想过吗~
  8. 【并查集】打击犯罪(ssl 2342)
  9. C#中的事件和委托(续)
  10. Docker启动MySql后连接报1251处理方法
  11. C51单片机————总线与系统扩展
  12. Android端直播系统开发入门
  13. 用python做自我介绍_使用Python实现自我介绍
  14. 专家不靠谱,秘笈才重要
  15. 安装fastadmin 该网页无法正常运作,将您重定向的次数过多
  16. 面试角度分析:微信里面让你删掉一个功能,你选哪个?
  17. ipa上架App Store流程
  18. C语言-函数-学会方程你的数学能力会乘风破浪突飞猛进-学会函数你的编程能力将百尺竿头更进一步
  19. opencv画框显示python_python+opencv选出视频中一帧再利用鼠标回调实现图像上画矩形框...
  20. Git:远程分支----git pull和git push命令用法介绍

热门文章

  1. 2021美食林全球餐厅精选榜公布,这里有一份美食地图请查收!
  2. QT qss选择器------后代选择器
  3. 基于AM5728 linux开源ethercat运动控制一体机解决方案
  4. 最小树形图-hdu4966
  5. 【聆听】泰戈尔诗集(二)
  6. makefile编写总结
  7. CLUSTER 05: 块存储应用案例 分布式文件系统 对象存储
  8. 国家/地区语言简写代码
  9. TSINGSEE青犀视频云-边-端架构视频智能分析平台EasyNVR如何实现直播地址和录像地址统一
  10. The Easter Proclamation (Exsultet) / 逾越颂