PAT Advanced Level
- 具有充分的英文阅读理解能力;
- 理解并掌握基础数据结构,包括:线性表、树、图;
- 理解并熟练编程实现经典高级算法,包括哈希映射、并查集、最短路径、拓扑排序、关键路径、贪心、深度优先搜索、广度优先搜索、回溯剪枝等;
- 具备较强的问题抽象和建模能力,能实现对复杂实际问题的模拟求解。
1、排序:快速排序,直接插入排序,希尔排序,分治排序,堆排序。
2、图论:拓扑排序(好像没考过)、最短路径、深度搜索、广度搜索。
3、树:树的遍历、完全二叉树、AVL,CBT,BST。
4、其他:并查集,模拟,哈希(二次探测一次,简单hash多次)、背包(一次),lcs(一次),最大子和(一次),set(一次),1057(分块搜索)
一些东西
整行读入字符串
string str;
getline(cin,str);//读入string
char str2[1024];
cin.getline(str2,1024);//读入char数组
string::erase
erase(pos,n):
删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符。
erase(position):
删除position处的一个字符(position是个string类型的迭代器)。
erase(first,last):
删除从first到last之间的字符(first和last都是迭代器)。
记模板
最大公约数
gcd(a,b)=gcd(b,a mod b)
int gcd(int a,int b)
{
if(a<b){int temp;temp=a;a=b;b=temp;} //使a>=b
if(b==0)return a;
return gcd(b,a%b);
}
最短路
floyd
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
dis[i][j]=dis[i][j]||(dis[i][k]&&dis[k][j]);
Dijkstra
struct edge
{
int to,cost;
};
vector<edge>v[1010];
typedef pair<int,int>p;
bool vis[1010];
int dis[1010];
int n;
void dijkstra()
{
fill(dis+1,dis+n+1,INF);
dis[1]=0;
priority_queue<p,vector<p>,greater<p> >q;
q.push(p(0,1));
while(!q.empty())
{
p temp=q.top();
q.pop();
int w=temp.first;int id=temp.second;
if(vid[id])continue;
vis[id]=true;
for(int i=0;i<v[id].size();i++)
{
edge &e=v[id][i];
if(w+e.cost<dis[e.to])
{
dis[e.to]=w+e.cost;
q.push(p(dis[e.to],e.to));
}
}
}
}
数位dp
int a[20];
long long dp[20][state];
long long dfs(int pos,/*state变量*/,bool lead,bool limit)
{
if(pos==-1) return 1;
if(!limit && !lead && dp[pos][state]!=-1) return dp[pos][state];
int up=limit?a[pos]:9;
ll ans=0;
for(int i=0;i<=up;i++)
{
if() ...
else if()...
ans+=dfs(pos-1,/*状态转移*/,lead && i==0,limit && i==a[pos])
}
if(!limit && !lead) dp[pos][state]=ans;
return ans;
}
long long solve(long long x)
{
int pos=0;
while(x)
{
a[pos++]=x%10;
x/=10;
}
return dfs(pos-1,/*一系列状态 */,true,true);
}
int main()
{
long long le,ri;
while(~scanf("%lld%lld",&le,&ri))
{
printf("%lld\n",solve(ri)-solve(le-1));
}
}
树状数组
(下标都从1开始)
区间查询 单点修改
int n;
int d[500010];
int lowbit(int x)
{
return x&(-x);
}
int query(int x)//查询前缀和
{
int res=0;
while(x)
{
res+=d[x];
x-=lowbit(x);
}
return res;
}
void add(int x,int v)//单点修改
{
while(x<=n)
{
d[x]+=v;
x+=lowbit(x);
}
}
int main()
{
int m,x,y,ope;
scanf("%d%d",&n,&m);
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
add(i,x);
}
while(m--)
{
scanf("%d%d%d",&ope,&x,&y);
if(ope==1)add(x,y);
else if(ope==2)printf("%d\n",query(y)-query(x-1));
}
return 0;
}
单点查询 区间修改
int n;
int c[500010];//差分数组
int lowbit(int x)
{
return x&(-x);
}
int query(int x)//单点查询
{
int res=0;
while(x)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
void add(int x,int v)//区间修改
{
while(x<=n)
{
c[x]+=v;
x+=lowbit(x);
}
}
int main()
{
int m,x,y,k,ope,ls;
scanf("%d%d",&n,&m);
memset(c,0,sizeof(c));
ls=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
add(i,x-ls);
ls=x;
}
while(m--)
{
scanf("%d",&ope);
if(ope==1)
{
scanf("%d%d%d",&x,&y,&k);
add(x,k);
add(y+1,-k);
}
else if(ope==2)
{
scanf("%d",&x);
printf("%d\n",query(x));
}
}
return 0;
}
二分
求满足条件的最大值
int l=1,r=maxn,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(judge(mid))ans=mid,l=mid+1;
else r=mid-1;
}
求满足条件的最小值
int l=1,r=maxn,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(judge(mid))ans=mid,r=mid-1;
else l=mid+1;
}
并查集
int par[1010],high[1010];
void init(int n)
{
for(int i=1;i<=n;i++)
{
par[i]=i;
high[i]=0;
}
}
int find(int x)
{
if(par[x]==x)return x;
return par[x]=find(par[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y)return;
if(high[x]<high[y])par[x]=y; //启发式合并
else
{
par[y]=x;
if(high[x]==high[y])high[x]++;
}
}
bool same(int x,int y)
{
return find(x)==find(y);
}
优先队列的优先级设置
struct fruit
{
string name;
double price;
}f1,f2,f3; //定义三个结构体变量
struct cmp
{
bool operator()(fruit f1, fruit f2) //重载括号
{
return f1.price<f2.price; //等同于less
}
};
调用:priority_queue<fruit,vector<fruit>,cmp>q;
AVL的插入
struct node
{
int val;
int high;
node *left,*right;
node(int x)
{
val=x;high=0;
left=right=NULL;
}
};
int gethigh(node *temp)
{
if(temp==NULL)return -1;
return temp->high;
}
node* SingleRotateLL(node *root)
{
node *temp;
temp=root->left;
root->left=temp->right;
temp->right=root;
root->high=max(gethigh(root->left),gethigh(root->right))+1; //更新高度
temp->high=max(gethigh(temp->left),gethigh(temp->right))+1;
return temp;
}
node *SingleRotateRR(node *root)
{
node *temp;
temp=root->right;
root->right=temp->left;
temp->left=root;
root->high=max(gethigh(root->left),gethigh(root->right))+1; //更新高度
temp->high=max(gethigh(temp->left),gethigh(temp->right))+1;
return temp;
}
node *DoubleRotateLR(node *root)
{
root->left=SingleRotateRR(root->left);
return SingleRotateLL(root);
}
node *DoubleRotateRL(node *root)
{
root->right=SingleRotateLL(root->right);
return SingleRotateRR(root);
}
node* Insert(node *root,int x)
{
if(root==NULL){return new node(x);}
if(x<root->val)
{
root->left=Insert(root->left,x);
if(abs(gethigh(root->left)-gethigh(root->right))>1)
{
if(x<root->left->val)
root=SingleRotateLL(root);
else
root=DoubleRotateLR(root);
}
}
else
{
root->right=Insert(root->right,x);
if (abs(gethigh(root->left)-gethigh(root->right))>1)
{
if(x>root->right->val)
root=SingleRotateRR(root);
else
root=DoubleRotateRL(root);
}
}
root->high=max(gethigh(root->left),gethigh(root->right))+1; //更新高度
return root;
}
int main()
{
int n,x;
scanf("%d",&n);
node *root=NULL;
while(n--)
{
scanf("%d",&x);
root=Insert(root,x);
}
printf("%d\n",root->val);
return 0;
}
题解
Nowcoder
1017
求栈的中位数,包括push和pop操作。
对于求中位数,二分+树状数组。
1038
求1~N十进制表示中1的个数。
数位dp。
$dp[i][j]$:长度为i已有j个1的数字中1的个数。
int dfs(int pos,int num,bool limit)
{
if(pos==-1)return num;
if(!limit&&dp[pos][num]!=-1)return dp[pos][num];
int up=limit?a[pos]:9;
int ans=0;
for(int i=0;i<=up;i++)
ans+=dfs(pos-1,i==1?num+1:num,limit&&i==up);
if(!limit)dp[pos][num]=ans;
return ans;
}
1049
给你一些数字的片段,希望拼接之后能拼出的最小的数字。
样例输入:5 32 321 3214 0229 87,样例输出:22932132143287。
假设有两个相邻的数字片段a,b。然后我们就要想,把a和b交换能不能使整个序列变小呢?这个问题的其实等价于b+a 是否小于a+b,也就是说对于这样一个序列,如果某两个相邻的元素之间发生交换可以使得整个序列的值变小,就应该交换。
注意00000的情况即可。
bool cmp(string x,string y)
{
if(x+y<y+x)return true;
return false;
}
PTA
1045
有一组喜欢的数字序列,要从另一组数字里面选出最长的子序列,使得喜欢的数字序列包含在子序列中(不需要每一个都被包含)。
可以把喜欢的数字序列从小到大编号,然后在数字里选出子序列就相当于最长非递减子序列。
1091
如果dfs要考虑深度,避免递归深度过大爆栈。
这题。所以用bfs。
1103
给出N,K,P,使得。输出的方案首先最大然后字典序最大。
dfs。注意写法。
dfs里面不要用循环写,因为要字典序最大,肯定是从最大的数开始枚举。
dfs(int id,int now, int cnt, int sum, int path[])
转移:
if(now+a[id]<=n)
{
path[cnt + 1] = id;
dfs(id,now + a[id], cnt + 1, sum + id, path);
}
if(id-1>=1)
dfs(id-1,now,cnt,sum,path);
调用:dfs(a[0],0, 0, 0, pp);
1123
判断是不是完全二叉树。当某个节点的儿子有为空的以后,出现子节点不为空的则说明不是完全二叉树,否则是。
1135
给出一个二叉查找树的前序遍历序列,判断该树是不是红黑树。
已知红黑树满足以下性质:
(1)每个结点要么是红的要么是黑的。
(2)根结点是黑的。
(3)每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。
(4)如果一个结点是红的,那么它的两个儿子都是黑的。
(5)对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。
这道题debug了好久…一直有几个点过不去,然后看题解发现是自己不清楚红黑树的定义。它的叶子并不是我之前所想的叶子。
如图是一棵红黑树:
此图忽略了叶子和根部的父结点。同时,上文中我们所说的 “叶结点” 或”NULL结点”,如上图所示,它不包含数据而只充当树在此结束的指示,这些节点在绘图中经常被省略。
然后改一下写的代码就可以过了。
1139
A想要联系B需要这样的步骤:A先找一个同性朋友C,再让C找一个与B同性且同时是C和B的D,由D联系B。现给出一些关系,给出A和B,输出可能的联系的方案,即输出C和D。编号都用四位数表示。
本来想的是DFS,这样会超时,其实已经规定了深度为4,所以只要枚举A的同性朋友C和B的同性朋友D,判断C和D是否是朋友即可。因为这里N最大为300,所以根据复杂度知道可行。
这里还有一些坑,比如男女用+-来表示,如果直接用int来接收的话,如果出现-0000就没法判断到底是+还是-了。还有输出的时候应该要%04d(注意!!!)。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!