PAT A

116 阅读10分钟

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;//当前映射的值
2map 可以根据键的值从小到大排序(内部红黑树完成)
/******cctype*/
#include<cctype>//ctype.h
0、函数isalnum():判断该字符是否alphanumeric 是返回true
1tolower():将大写字符转换成对应小写
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和某窗口有关信息全部打包放进)