8.3
A1051 Pop Sequence ——Stack
- 注意变量初试化的位置
- 注意每次push都要检查是否溢出
for(int i=0;i<K;i++){
stack <int> s;
int flag=1;
int max_pop=0;
int pre_node=0;
for(int j=0;j<N;j++){
int node;
scanf("%d",&node);
if(node>pre_node){
if((node-max_pop)<=M){
for(int k=max_pop+1;k<=node;k++){
s.push(k);
if(s.size()>M) flag=0;//!
}
if(s.top()>max_pop) max_pop=s.top();
s.pop();
pre_node=node;
}
else flag=0;
}
else{
if(s.top()!=node){
flag=0;
}
else {
pre_node=node;
s.pop();
}
}
}
if(flag==0) printf("NO\n");
else printf("YES\n");
}
A1056 Rice And Mice——需重做
- 问题:在不使用sort的情况下排名 Rank与every Turn中人数的关系
- queue 容器的使用
- 核心代码如下
int temp=Np;int group;
while(q.size()>1){
vector <int> v;
if(temp%Ng==0) group=temp/Ng;
else group=temp/Ng+1;
for(int j=0;j<group;j++){
int win;int max=-1;
for(int i=0;i<Ng&&q.empty()==false;i++){
if(M[q.front()].weight>max){
win=q.front();
max=M[win].weight;}
**M[q.front()].rank=group+1;//核心**
q.pop();
}
v.push_back(win);
}
for(int k=0;k<v.size();k++)
q.push(v[k]);
temp=group;
}
8.4
A1074——反转链表
- 问题:反转后子串连接问题——上一个子串的rear如何与下一个子串的新头连接
- 考虑找新头的条件(继续反转的条件)
int NewHead=Head;
int count=sum;//注意无效点的剔除
int rear=Head;
int OldHead=Head;
if(count>=K)
for(int j=0;j<K-1;j++)
NewHead=List[NewHead].next;
int NewAddress=NewHead;//保存新链表表头
while(count>=K){
int p=NewHead;
NewHead=List[NewHead].next;//在反转前移动NewHead至next
/*反转过程*/
while(p!=rear){
List[p].next=NToA[p];//采用在输入数据时保存数组Next To Address来实现反转
p=List[p].next;
}
count-=K;
OldHead=NewHead;
if(count>=K){
for(int j=0;j<K-1;j++)
NewHead=List[NewHead].next;
List[rear].next=NewHead;
rear=OldHead;
}
}
List[rear].next=NewHead;
Tips: 更简便的思想:先写出反转后数字列表,再对照地址打印(注意无效结点的消除)
for (int i = 0; i < sum; i++)
result[i] = list[i];
for (int i = 0; i < (sum - sum % k); i++)
result[i] = list[i / k * k + k - 1 - i % k];
for (int i = 0; i < sum - 1; i++)
printf("%05d %d %05d\n", result[i], data[result[i]], result[i + 1]);
printf("%05d %d -1", result[sum - 1], data[result[sum - 1]]);
8.6
DFS与BFS
- DFS——找到岔道口和死胡同
典型问题:枚举从N个整数中选择K个数的所有方案(对每个点都有“选”与“不选”两条岔路)
//A为死胡同条件,B为结果约束1,C为结果约束2(更新result的依据)
vector<int>tmp,ans;
void DFS(int index,int A,int B,int C)
{
if(满足条件A){
if(B&&C)
/*更新结果*/
ans=tmp;
}
return;
if(剪枝条件) return;
tmp.push_back(index);
DFS(index+1,更新A,B,C);//加入index操作(不可重复输入,若可重复加入index,写作DFS(index,更新A,B,C);
tmp.pop_back();
/*not select index*/
DFS(index+1,A,B,C);
}
- BFS——队列的应用(适用问题:扫雷式搜索)
模板:
//s为start point
void BFS(int s)
{
queue<int> q;
q.push(s);
while(q.empty()==false){
int top=q.front();
q.pop();
将top的下一层未层入队的结点全部入队,并更新为已入队;
}
}
Tips:
- 处理上下左右前后移动坐标的方法
增量数组
int X[]={0,0,1,-1};
int Y[]={1,-1,0,0};
空间坐标再加一组即可(6个坐标)
- STL容器queue使用注意事项
元素入队的push操作为一个副本,无法通过该副本修改原元素(反之亦然),可通过队列中存放元素编号来解决此问题
A1091——Acute Stroke超时重做
8.6&8.7
树的新建、修改和插入
树的遍历
- 二叉树的遍历
先序、中序、后序的递归方法
层序(利用队列)
中序与其他三种遍历结合求唯一二叉树
- 树的遍历
DFS和BFS
/*DFS*树的先根遍历*/
struct Node{
int data;
vector<int> child;
}Chain[maxn];
void DFS(int root){
printf("%d",Chain[root].data);
for(int i=0;i<Chain[root].child.size();i++)
DFS(Chain[root].child[i]);
}
/*DFS中常用判断是否叶节点方法if(Chain[root].child.size()==0)*/
/*BFS*/
queue<int> q;
q.push(root);
while(q.empty()==false){
int top=q.front();
printf("%d",Chain[top].data);
q.pop();
for(int i=0;i<Chain[top].child.size();i++){
int child=Chain[top].child[i];
q.push(child);
}
}
Tips:
- 有关cmp函数
bool cmp(int a,int b){
return Node[a].data>Node[b].data;
}
- 好的方法
A1094 可用hashTable记录每一代数量
- 易犯错误:double 变量的输入格式
"%lf"
8.8
BST
基本操作
A1064——完全二叉树和二叉搜索树的结合 注意在递归填入树结点时在输入时记录数据的数组要设成全局变量
递归填入结点过程
int sequence[maxN];//
int Tree[maxN];//完整二叉树待填入数组
//处理前sort(sequence,sequence+N+1,cmp);
void fill(int N,int l,int r,int index)
{
if(N==0) return;
int ck=floor(log(N+1)/log(2));
int remainder=N-(power(2,ck)-1);
int nleft,nright;
if(remainder<=power(2,ck-1)){
nleft=power(2,ck-1)-1+remainder;
nright=N-nleft-1;
}
else{
nleft=power(2,ck)-1;
nright=N-nleft-1;
}
int root=l+nleft;
Tree[index]=sequence[root];//!!!!
fill(nleft,l,root-1,index*2);
fill(nright,root+1,r,index*2+1);
}
8.10
基本用法不够熟练
AVL树
并查集
/*3 steps*/
1.initial
for(int i=0;i<N;i++)
father[i]=-1;
2.find father
int Findfather(int v)
{
if(father[v]<0) return v;
else{
int F=Findfather(father[v]);
father[v]=F;
return F;
}
}
3.union
void union(int v1,int v2)
{
int faA=FindFather(v1);
int faB=FindFather(v2);
if(faA!=faB){
if(father[faA]<father[faB]){
father[faA]+=father[faB];
father[faB]=faA;
}
else{
father[faB]+=father[faA];
father[faA]=faB;
}
}
}
堆
待整理序列从1开始
void downAdjust(int low,int high)/*大顶堆*/
{
int j=low*2;/*start from 0——low*2-1*/
if(j<=high){
if(j+1<=high&&heap[j+1]>heap[j]) j=j+1;
if(heap[j]>heap[low]){
swap(heap[j],heap[low]);
low=j;
j=low*2;
}
else break;
}
}
void createHeap(int N)
{
for(int i=N/2;i>=1;i--)
downAdjust(i,N);
}
void heapsort(int N)
{
createHeap(N);
for(int i=N-1;i>1;i--){
swap(heap[i],heap[1]);
downAdjust(1,i-1);
}
}
A1098 Insertion or Heap Sort
Tips:
-
在判断两种排序时可采取
if not Insertion else Heap -
插⼊入排序的特点是:部分排序数组前面的顺序是从小到大的,后面的顺序不一定,但一定和原序列的 后面的顺序相同。所以只要遍历一下前面几位,遇到不是从小到大的时候,开始看partseq和初始序列是不是对应位置相等的,相等就说明是插入排序
-
插入排序的下一步:找到未排序的第一位(即不满足
while(i<=N&&partseq[i-1]<partseq[i]){ i++;index=i;}然后sort(partseq+1,partseq+index+1,cmp) -
Heap的下一步:由于其序列后面有序,即找到比未排序序列最大值(堆顶)的第一个数p(位置,从序列尾部开始找)swap,downAdjust(1,p-1)
哈夫曼树
8.11
图算法专题
- 定义及相关术语
1、顶点(vertex)边(Edge) G(V,E)
2、有向图和无向图
3、顶点的度:和该顶点相连的边的条数。对有向图而言(出顶点边数——出度,入顶点边数——入度)
4、点权和边权
- 图的存储
1、邻接矩阵
G[i][j]=1 说明顶点i与顶点j之间有边(该矩阵内也可以存储边的权值)
G[i][j]=0 说明两个顶点之间没有边
适用于顶点数目不超过1000的题目
2、邻接表
只存放每条边的终点编号
vector<int> Adj[N];添加顶点Adj[i].push_back(j);
同时存放边权
建结构体
struct Node{
int v;
int weight;
};
vector<Node> Adj[N];
定义结构体的构造函数方便对结构体赋值
struct Node{
int v,w;
Node(int _v,int _w):v(_v),w(_w){};
};
Adj[i].push_back(Node(v,w));
- 图的遍历
1、采用DFS
/*伪码描述*/
DFS(u)
{
vis[u]=true;
//对u操作
for(从u出发可到达的所有顶点v){
if(vis[v]==false)
DFS(v);
}
}
DFSTraversal(G)//遍历图G
{
for(图G的所有顶点u)
if(vis[u]==false)
DFS[u];
}
2、BFS
/*伪码描述*/
BFS(u)
{
queue q;
q.push(u);
inq[u]=true;
while(q.empty()==false){
访问队首元素;
q.pop();
for(从u出发可到达的所有顶点v)
if(inq[v]==false){
q.push(v);
inq[v]=true;
}
}
}
BFSTraversal(G)
{
for(G的所有顶点u)
if(inq[u]==false)
BFS(u);
}
8.12
图的遍历应用
A1013
1、如何判定图的连通性——图的遍历or并查集
2、图的遍历(DFS)
3、并查集
4、如何处理删除结点(如果某点被occupied,该点与其他点失联,相当于删除结点)
/*DFS*/
vector<int> G[maxN];
bool vis[maxN]={false}
int occupy;
void DFS(int u)
{
if(u==occupy) return;//delete the occupied node
vis[u]=true;
for(int i=0;i<G[u].size();i++)
if(vis[G[u][i]]==false)
DFS(G[u][i]);
}
int block=0;
for(int i=1;i<=N;i++){
if(i!=occupy&&vis[i]==false){
DFS(i);
block++;
}
}
/*并查集*/
for(int u=1;u<=N;u++){
for(int v=0;v<G[u].size();v++){
if(u==occupy||G[u][v]==occupy) continue;//
Union(u,v);
}
}
int block=0;
for(int i=1;i<=N;i++){
if(i==occupy) continue;
int fa_i=father(i);
if(vis[fa_i]==false) block++;
vis[fa_i]=true;
}
Tips:
/*初始化vis*/
#include<string.h>
memset(vis,false,sizeof(vis);
A1021
1、注意对题目中N个顶点,N-1条边的理解:如果连通,则必然是树形
2、可证明,经过两次DFS遍历:第一次任选结点遍历,第二次从第一次遍历得到的最深叶节点集合(A)中任选一点遍历得到最深叶节点集合(B),A与B的并集即是答案
3、 遍历每一个结点计算深度记录也可
int deepest=0;
void DFS(int u,int depth)
{
vis[u]=true;
for(int i=0;i<G[u].size();i++)
if(vis[G[u][i]]==false)
DFS(G[u][i],depth+1);
if(deepest<depth) deepest=depth;
}
A1034
1、处理字符串:map
2、如何计算环形的边权
3、注意题目中叙述N<=1000,N:the number of phone calls,所以数组maxN>2000
#include<map>
#include<string>
using namespace std;
map<int,string> intTostring;
map<string,int> stringToint;
map<string,int> Gang;//存储头目姓名和团伙人数,map可自动排序
int num=0;
int change(string str)
{
/*可在stringToint找到str*/
/*find(key)返回键为key的映射的迭代器*/
if(stringToint.find(str)!=stringToint.end())
return stringToint[str];
else{
stringToint[str]=num;
intTostring[num]=str;
return num++;
}
}
/*输出*/
map<string,int>::iterator it;
for(it=Gang.begin();it!=Gang.end();it++)
cout<<it->first<<" "<<it->second<<endl;
int VertexWeight[maxN];
void DFS(int u,int &head,int &numperson,int &totalweight)//使用引用在迭代过程中可改变其值
{
if(VertexWeight[head]<VertexWeight[u]){
head=u;
}
vis[u]=true;
numperson++;
for(int i=0;i<N;i++){//不可利用对称矩阵?i=u+1
if(G[u][i]>0){//
total+=G[u][i];
G[u][i]=G[i][u];//防止重复计算边权
if(vis[i]==false) DFS(i,head,numperson,totalweight);
}
}
}
8.13
图论——最短路径问题
- Dijkstra算法
/*伪码*/
//G为图,d[]为源点到各点的最短路径长度,s为起点
Dijkstra()
{
initial;
for(循环n次)//n个结点
{
u=使d[u]最小的还未被访问的顶点标号;
标记u被访问;
for(从u出发能到达的所有顶点v){
if(v未被访问&&以u为中介点可优化s到v的距离d[v])
优化d[v];
}
}
}
问题模板
最短路径问题:第一标尺——距离,第二标尺(边权、点权、最小路径数),记录最短路径
较适用于标尺大于三的情况
/*Dijkstra&DFS*/
#include<algorithm>/*fill函数头文件*/
using namespace std;
const int INF=0x3fffffff;
vector<int> path[maxN];
bool vis[maxN]={false};
int dis[maxN];
int G[maxN][maxN];
/*初始化图在main中已完成*/
void Dijkstra(int s)
{
fill(dis,dis+maxN,INF);
dis[s]=0;//注意赋值时s不是0
for(int i=0;i<N;i++){
int u=-1;int mind=INF;
for(int j=0;j<N;j++)
if(vis[j]==false&&dis[j]<mind){
u=j;
mind=dis[j];
}
if(u==-1) return;//not connect
vis[u]=true;
for(int v=0;v<N;v++){
if(vis[v]==false&&G[u][v]!=INF){
if(d[u]+G[u][v]<d[v]){
d[v]=d[u]+G[u][v];
path[v].clear();
path[v].push_back(u);
}
else if(d[u]+G[u][v]==d[v]){
path[v].push_back(u);
}
}
}
}
}
int optvalue;
vector<int> temp,ans;
void DFS(int v)
{
if(v==s)//s为起点
{
temp.push_back(v);
int value;
/*计算temp路径的value*/
if(value优于optvalue){
optvalue=value;
ans=temp;
}
temp.pop_back();
return;
}
temp.push_back(v);
for(int i=0;i<path[v].size();i++)
DFS(path[v][i]);
temp.pop_back();
}
8.14
A1018
注意:此题send和back在路径上的传递不满足最优子结构(不是简单相加过程),只有所有路径确定后才可做选择
int send=INF,back=INF;
vector<int> path,temp;
void DFS(int v)
{
if(v==0){
temp.push_back(v);
int need=0,remain=0;
for(int u=temp.size()-2;u>=0;u--){
int id=temp[u];
if(Bikes[id]<=0){
if(remain<fabs(Bikes[id])){
need=need+fabs(Bikes[id])-remain;
remain=0;}
else remain+=Bikes[id];
}
else remain+=Bikes[id];
}
if(need<send){
send=need;
back=remain;
path=temp;
}
else if(need==send&&remain<back){
back=remain;
path=temp;
}
temp.pop_back();
return;
}
temp.push_back(v);
for(int i=0;i<pre[v].size();i++)
DFS(pre[v][i]);
temp.pop_back();
}
A1072不明原因错误
1、M个gas stationd都要算进图中(并非未选中的station就抛掉)——仔细分析样例
2、注意标号(Dijkstra中)
3、注意循环内外变量设置(循环开始时是否需要初始化)
4、注意字符串的处理
for(int i=1;i<=M;i++){
fill(vis,vis+maxN,false);
distance.clear();
Dijkstra(N+i);
double sum=0;
int k;
int distance=INF;
for(k=1;k<=N;k++){
if(dis[k]>Ds) break;
sum+=dis[k]*1.0;
if(dis[k]<distance) distance=dis[k];
}
if(k==N+1){
double average=round(sum/N);
if(maxdis<distance){
maxdis=distance;
minave=average;
id=i;
}
else if(maxdis==distance&&average<minave){
minave=average;
id=i;
}
}
}
if(id==-1) printf("No Solution");
else{
printf("G%d\n",id);
printf("%.1f %.1f",maxdis,minave);
}
- A1087
0、Dijkstra+DFS+map
1、注意标号
2、注意Dijkstra中使dis最小得方案数不等于dis[Distinition]
/*Dijkstra*/
const int INF=0x3fffffff;
bool vis[maxN]={false};
int G[maxN][maxN];
int weight[maxN];
int dis[maxN];
map<string,int> stringToint;
map<int,string> intTostring;
int N,K;
vector<int> pre[maxN];
void Dijkstra(int s)
{
fill(dis,dis+maxN,INF);
dis[s]=0;//
for(int i=0;i<N;i++){
int u=-1;int mind=INF;
for(int j=0;j<N;j++){
if(vis[j]==false&&dis[j]<mind){
u=j;
mind=dis[j];
}
}
if(u==-1) return;
vis[u]=true;
for(int v=0;v<N;v++){
if(vis[v]==false&&G[u][v]!=INF){
if(dis[u]+G[u][v]<dis[v]){
dis[v]=dis[u]+G[u][v];
pre[v].clear();//
pre[v].push_back(u);
}
else if(dis[u]+G[u][v]==dis[v])
pre[v].push_back(u);
}
}
}
}
/*DFS*/
vector<int> path,temp;
int maxhap=0;int maxave=0;
int num=0;//记录方案数
void DFS(int v)
{
if(v==0){
temp.push_back(v);
num++;
int total=0;
for(int i=temp.size()-2;i>=0;i--)
total+=weight[temp[i]];
double average=1.0*total/(temp.size()-1);
if(total>maxhap){
maxhap=total;
maxave=average;
path=temp;
}
else if(total==maxhap&&average>maxave){
maxave=average;
path=temp;
}
temp.pop_back();
return;
}
temp.push_back(v);
for(int i=0;i<pre[v].size();i++)
DFS(pre[v][i]);
temp.pop_back();
}
最短路径问题总结
1、模板Dijkstra+DFS
2、注意初始化(main()中、Dijkstra()中): dis[],G[][],vis[],dis[start]=0
#include<algorithm>
const int INF=0x3fffffff;
using namespace std;
fill(G[0],G[0]+maxN*maxN,INF);
3、注意标号(影响输入、Dijkstra)
4、注意做题前列出第一标尺、第二标尺等;注意样例
5、注意输入输出:string一般用cin,cout
6、字符串处理问题
8.14 数学问题
- 最大公约数和最小公倍数
/*最大公约数*/
int gcd(int a,int b)
{
if(b==0) return a;
else return gcd(b,a%b);
}
/*最小公倍数*/
d=gcd(a,b);
int lcm=a/d*b;//为避免a*b溢出
- 分数的四则运算
/*分数的表示与化简*/
struct Fraction{
int up,down;
};
/*化简满足三项要求:
1、保持分子携带符号(若分母为负,分子分母反号)
2、若分子为0,则令分母为1
3、约分:求出分子分母绝对值的最大公约数d,同除*/
/*abs头文件<stdlib.h>*/
Fraction reduction(Fraction result)
{
if(result.down<0){
result.up=-1*result.up;
result.down=-1*result.down;
}
if(result.up==0)
result.down=1;
else{//注意:分子不为0约分
int d=gcd(abs(result.up),abs(result.down));
result.up/=d;
result.down/=d;
}
return result;
}
四则运算注意:最后返回结果时要先化简reduction
注意除法在用公式前要先判定被除分子是否为0
long long
/*分数的输出*/
/*输出前化简、注意分母为1时输出整数、带分数形式输出*/
void showresult(Fraction r)
{
r=reduction(r);
if(r.down==1) printf("%lld",r.up);//
else if(abs(r.up)>abs(r.down))
printf("%d %d/%d",r.up/r.down,abs(r.up)%r.down,r.down);
else
printf("%d/%d",r.up,r.down);
}
- 质数
bool prime(int n)
{
if(n<=1) return false;//
for(int i=2;i<=sqrt(n);i++){
if(n%i==0) return false;
}
return true;
}
/*埃氏筛法:对每一个素数筛去其倍数。设当前数字为a,从a=2开始,从小到大到达某数a时,如果a没有被前面的数筛掉,则a是素数*/
int prime[maxN],pnum=0;
bool p[maxN]={false};
void Find_Prime()
{
for(int i=2;i<maxN;i++){
if(p[i]==false){
for(int j=i+i;j<maxN;j+=i)
p[j]=true;
}
}
}
- 应用于Hash表中:A1078
注意:Quadratic probing(with positive increments only)的查找上限(找不到)是TSize(素数处理后)
- 质因子分解:将一个正整数n写成一个或多个质数乘积的形式,n>1
struct factor{
int x,cnt;
}fac[10];//对于int型来说数组大小为10即可
/*根据结论:对一个正整数来说,其质因子最多只有一个>sqrt(n),其余均<=sqrt(n)*/
1、枚举[2,sqrt(n)]内n的质数,判断其是否是n的质因子,设为p,加入factor结构体,初始化cnt=0;
只要p还是n的因子,令n不断除p,cnt++,直到p不再是n的因子;
if(n%prime[i]==0){
fac[num].x=prime[i];
fac[num].cnt=0;
while(n%prime[i]==0){
fac[num].cnt++;
n/=prime[i];
}
num++;
}
2、若上述枚举结束后n>1,则说明n有一个>sqrt(n)的因子;
if(n!=1){
fac[num].x=n;
fac[num].cnt=1;
}
- 大整数运算:用基本数据类型无法存储其精度的整数
1、存储
用数组倒序存储:整数的高位存储在数组的高位,个位存储在首位
struct bign{
int d[1000];
int len;
bign(){
memset(d,0,sizeof(d));
len=0;
}
};
char str[1000];//scanf
bign change(char str[])
{
bign a;
a.len=strlen(str);
for(int i=0;i<a.len;i++)
a.d[i]=str[a.len-i-1]-'0';
return a;
}
2、四则运算
bign add(bign a,bign b)
{
bign c;
int carry=0;
for(int i=0;i<a.len||i<b.len;i++){
int temp=a.d[i]+b.d[i]+carry;
c.d[c.len++]=temp%10;
carry=temp/10;
}
if(carry!=0)
c.d[c.len++]=carry;
return c;
}
bign sub(bign a,bign b)
{
bign c;
for(int i=0;i<a.len||i<b.len;i++){
if(a.d[i]<b.d[i]){
a.d[i+1]--;
a.d[i]+=10;
c.d[c.len++]=a.d[i]-b.d[i];
}
}
while(c.len-1>=1&&c.d[c.len-1]==0)
c.len--;
return c;
}
/*注意:上述加法运算针对非负,若有一负,应用减法
减法应注意大减小*/
bign multi(bign a,int b)
{
bign c;
int carry=0;
for(int i=0;i<a.len;i++){
int temp=a.d[i]*b+carry;
c.d[c.len++]=temp%10;
carry=temp/10;
}
while(carry!=0){
c.d[c.len++]=carry%10;
carry/=10;
}
return c;
}
8.15-8.16 简单数学
-
A1069 数字黑洞
-
A1104 数字的片段和*重做
-
A1049 counting ones*重做
The task is simple: given any positive integer N, you are supposed to count the total number of 1's in the decimal form of the integers from 1 to N. For example, given N being 12, there are five 1's in 1, 10, 11, and 12.
考虑当前位可能出现情况(A1104、A1049)
- A1059 Prime Factors
0、质因子分解
1、题目中说在long int(等同于int)范围内,素数表开10^5(<sqrt(N)) 即可
2、注意特判1=1
- A1096 consecutive factors*重做
核心:N的因子小于等于sqrt(N)
- A1023
0、高精度乘法模板:注意每位要加上carry,注意bign结构体内要初始化,注意change转化函数内字符换数字要-'0'
- A1024
0、大整数运算的判断:N在执行100次以后范围早已超过long long
1、algorithm 下的reverse函数
reverse(n.d,n.d+n.len);//n为bign型
8.17-8.18 排序
- A1016*
0、核心问题:如何配对
1、25分的题控制代码行数小于70
- A1028
用cin,cout有可能超时
- A1055*
0、注意观察所给数据,去掉无效数据
#include<iostream>
#include<vector>
#include<algorithm>
#include<string.h>
vector<node> v(N),_v;
vector<int> Age(205,0);//给vector型赋初值
- A1075*
注意最后一个测点(有满绩重复提交)
- 1095*
0、注意题目所给查询信息的有序性
1、注意动态处理的思维
2、map的用法(用printf输出)
printf("%s",mapp->first.c_str());
8.19
- map、string、头文件cctype
/*****map*/
#include<iostream>
#include<string>
#include<map>
using namespace std;
map<string,int> mapp;
string str;
0、mapp[str]++;//可直接进行++计算而不用初始化
1、通过迭代器访问:
for(map<string,int>::iterattor it=mapp.begin();it!=mapp.end();it++)
it->first;//当前映射的键
it->second;//当前映射的值
2、map 可以根据键的值从小到大排序(内部红黑树完成)
/******cctype*/
#include<cctype>//ctype.h
0、函数isalnum():判断该字符是否alphanumeric 是返回true
1、tolower():将大写字符转换成对应小写
quote:
Converts c to its lowercase equivalent if c is an uppercase letter and has a lowercase equivalent.
If no such conversion is possible, the value returned is c unchanged.
/******string*/
operator+=;
string加法可直接拼接两个string
- 动态规划
1、最大连续子列和
设有N个数组成的排列A[N]
dp[i]表示以i为末尾的最大连续子列和
边界:dp[0]=A[i];
递推式:dp[i]=max(dp[i-1]+A[i],A[i]);
A1007
注意只有一个正数的情况最大值计算不能在填dp数组内完成
2、 最长回文串长度
设有一串字符串string str;
dp[i][j]表示从i到j的子串,dp[][]=1表示该子串是回文,=0表示不是
int ans=1;//记录最长回文串长度
边界:d[i][i]=1;
if(str[i]==str[i+1])//注意i+1<str.length()
d[i][i+1]=1;//此时回文串长度为2
int len=str.length;
递推式:
if(str[i]==str[j]&&d[i+1][j-1]==1){
d[i][j]=1;
}
/**/
for(int l=3;l<=len;l++){
for(int i=0;i<len;i++){
int j=i+l-1;
if(str[i]==str[j]&&d[i+1][j-1]==1)
d[i][j]=1;
ans=l;
}
}
3、最长不下降子列
设数字串A[N]
dp[i]表示以i为末尾的最长不下降子列长度
边界:for(int i=0;i<N;i++)
dp[i]=1;
递推式:对每一个j(j>=0&&j<i)
dp[i]=max(dp[j]+1,dp[i]);//注意括号里必须是dp[i]而不是1
A1045
0、 可用最不下降子列,只需重新定义数字大小关系
1、 注意去掉待查数据的无效结点(Eva不喜欢的数是无效的)
4、最长公共子序列(LCS)
设有两个序列A,B(序号均从1到N)
dp[i][j]表示A序列的第i个元素之前和B序列的第j个元素之前的最长公共子列长度
边界:dp[0][j]=0;dp[i][0]=0;
递推式:
if(A[i]==B[j]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
A1045??
允许公共部分产生重复元素
修改后递推式:
if(A[i]==B[j]) dp[i][j]=max(dp[i-1][j],dp[i][j-1])+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
8.20-8.21
- 快乐模拟
*A1105
A1014
0、注意边界要求(在17:00之后进线的人输出sorry)
1、注意存储载体的选用(可将j和某窗口有关信息全部打包放进)