0.(森森美图)判断一个点x3,y3在一条直线(由x1,y1和x2,y2组成)的哪一边
若(y2-y3)/(x2-x3) - (y1-y3)/(x1-x3)>0 逆时针方向
否则顺时针方向
1.vector
vector<node>ve;//定义
ve.insert(ve.begin()+i,k);//中间插入
ve.insert(ve.begin()+i,num,key);
ve.erase(ve.begin()+i);//删除
ve.erase(ve.begin()+i,ve.end());
reverse(ve.begin(),ve.end());//翻转
ve.erase(unique(ve.begin(),ve.end()),ve.end());//去重
ve.pop_back();//pop掉最后一个
int x=lower_bound(ve.begin(),ve.end(),1)-ve.begin();//二分查找
维护一个有序的vector
vector<int>::iterator it;
it=lower_bound(ve.begin(),ve.end(),20);//不减首地址 就返回迭代器 找>=
ve.insert(it,20);//it作为地址
练习:http://acm.hdu.edu.cn/showproblem.php?pid=4841 (圆桌问题)
题意:给你2n,循环从左到右数,1-m,1-m这样数,数到m的人为坏人,数到的人出局(好人:坏人=1:1)
求好人坏人结果序列
思路:因为要出局,所以vector动态更新,数到的人就erase。
#include<bits/stdc++.h>
using namespace std;
vector<int>ve;
set<int>se;
int main()
{
int i,j,n,m,f=0;
while(cin>>n>>m){
ve.clear();se.clear();
for(i=1;i<=2*n;i++){
ve.push_back(i);
}
int pos=0;
// if(f)cout<<endl;
while(ve.size()>n){
pos=(pos+m-1+ve.size())%ve.size();
ve.erase(ve.begin()+pos);
}
for(i=0;i<ve.size();i++){
se.insert(ve[i]);
}
for(i=1;i<=2*n;i++){
if(se.count(i))cout<<"G";
else cout<<"B";
if(i%50==0)cout<<endl;
}
i--;
if(i%50!=0)cout<<endl;
f=1;
cout<<endl;
}
return 0;
}
View Code
2.队列
q.back() // 返回队尾元素
3.优先队列
priority_queue<int> qu;默认从大到小
priority_queue<int,voctor<int>,greater<int> > qu;从小到大
struct node{
int data;
friend bool operator <(node a,node b)
{
return a.data<b.data;
}
};
priority_queue<node>qu;
4.链表(插入删除都是O(n),而vector查询是O(n);两个刚好互补
list<int>li;
for(i=1;i<=n;i++)li.push_back(i);//插入
list<int>::iterator it;
for(it=li.begin();it!=li.end();it++){
if(num%k==0)it=li.erase(it),it--;//删除,返回迭代器
num++;
}
练习:http://acm.hdu.edu.cn/showproblem.php?pid=1276 (士兵人数训练问题)
题意:n个人,1-n编号。1212报数,报到2的出局,剩下的123123报数,报到3的出局,往复循环,剩下人数<=3结束。
求剩下人的编号
思路:因为反复删除,vector受不了,要用链表list来每次删除,修改指针。
注意:链表的erase操作在执行完的时候iterator也被销毁了,这样的话关于iterator的操作就会报错
迭代器遍历时erase操作就要注意这种情况
#include<bits/stdc++.h>
using namespace std;
list<int>li;
int main()
{
int i,j,n,m,f=0;
cin>>m;
while(m--){
cin>>n;
li.clear();
for(i=1;i<=n;i++){
li.push_back(i);
}
list<int>::iterator it;
int num=2;
while(li.size()>3){
int sum=0;
for(it=li.begin();it!=li.end();){
sum++;
if(sum%num==0)it=li.erase(it);
else it++;
}
num==2?num++:num--;
}
for(it=li.begin();it!=li.end();it++){
if(it!=li.begin())cout<<' ';
cout<<*it;
}
cout<<endl;
}
return 0;
}
View Code
for(it=li.begin();it!=li.end();){
sum++;
if(sum%num==0)it=li.erase(it);
else it++;
}
5.set
se.insert(se.begin(),9);//插入
se.erase(se.begin());//删除
se.erase(9);//可以直接写数字
set<int>::iterator it=se.lower_bound(1);//返回迭代器
set<int>::iterator it2=se.find(1);
se.count(23)//判断set容器里是否有该数
6.全排列
do{
for(i=0;i<3;i++)cout<<a[i]<<' ';
}while(next_permutation(a,a+3));
7.反向迭代器(reverse只有vector能用--而反向迭代器都可用)
vector<int>::reverse_iterator it;
for(it=ve.rbegin(); it!=ve.rend(); it++)
{
cout<<*it<<endl;
}
8.isalpha()判断是否是字母 isdigit()判断是否是数字
9.char字符串常用函数
char *strstr(const char *string, const char *strSearch); //查找函数;下面有写
strcpy(demo,s+2);//从s+2的地址开始赋值给demo
int strcmp(const char *string1, const char *string2); //比较函数
其中strstr函数比string中的find要快
char s[20]="abababaaa";
char demo[20]="abagaaa";
char *t;
t=strstr(s,demo);
if(t==NULL)cout<<"NULL";//为空
else cout<<t<<endl;//输出指针指向的第一个字符串
10.string字符串常用库函数
s.replace(0,2,"23U");//下标0开始的 2两个字符串 替换为23U
string ss=s.substr(1,4);//截取,从1开始,后面一个数字不填则取到结尾
findd=s.find("11");
11.从s+1字符串开始取->作为数字
char s[10];
scanf("%s",s);
int x;
if(s[0]=='-')sscanf(s+1,"%d",&x);
else sscanf(s,"%d",&x);
12.堆排序(大顶堆 小顶堆就是堆排序的结果)
堆排序思路:以大根堆为例:
第一步:从最后一个父节点开始;往上走。如果孩子节点>父节点则调换位置,然后往下更新孩子节点,因为小的换下来了,所以要更新。
第二步:把第一个节点和最后一个节点换位置,这样最后一个节点就是最大值。然后就是第一步,不过这次直接更新父节点即可,不用从最后一个父亲节点开始到根节点。
因为只有根节点换到了小的值。
动画演示:(知乎https://zhuanlan.zhihu.com/p/124885051
for(i=0;i<n;i++)cin>>a[i],make_heap(a,a+i+1,greater<int>());
//按输入序建立小顶堆:(父节点的值要比孩子节点的都要小)
void update(int start,int maxxn)
{
int dad=start;
int son=dad*2+1;//这里注意先给初值,在while里再更新
while(son<maxxn){
if(son+1<maxxn&&pre2[son+1]>pre2[son])son++;
if(pre2[son]<pre2[dad])break;
swap(pre2[son],pre2[dad]);
dad=son;
son=dad*2+1;
}
}
void solve(int maxxn)
{
for(int i=maxx;i>=0;i--){
update(i,n);//init 每个父节点都更新
}
for(int i=n-1;i>=0;i--){
swap(pre2[i],pre2[0]);//取得最大值
update(0,i);//再去0节点往下更新
}
}
13.两个队模拟栈,两个栈模拟队列
了解大致思想即可
14.ALV 平衡二叉树(空树 or 左右子树深度差不超过1 的 二叉搜索树)
二叉搜索树:左子树比它小,右子树比他大
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
struct node{
int data,height;
struct node *l,*r;
};
int deep(node *p)
{
if(p==NULL)return 0;//這個 return 0而不是1
return max(deep(p->l),deep(p->r))+1;
}
node *ll_change(node *y)
{
node *x=y->l;
y->l=x->r;
x->r=y;
return x;//這裏return錯了 是x而不是y!!
}
node *rr_change(node *y)
{
node *x=y->r;
y->r=x->l;
x->l=y;
return x;//這裏return錯了 是x而不是y!!
}
node *lr_change(node *y)
{
y->l=rr_change(y->l);
return ll_change(y);
}
node *rl_change(node *y)
{
y->r=ll_change(y->r);
return rr_change(y);
}
node * build(node *root,int x)
{
if(root==NULL){
node *p=new node;
p->l=p->r=NULL;
p->data=x;
p->height=1;
return p;
}
if(x<root->data)root->l=build(root->l,x);
else root->r=build(root->r,x);
root->height=deep(root);
int balance=deep(root->l)-deep(root->r);
if (balance > 1 && x < root->l->data) //LL型
return ll_change(root);
if (balance < -1 && x >root->r->data) //RR型
return rr_change(root);
if (balance>1 && x > root->l->data) //LR型
return lr_change(root);
if (balance < -1 && x <root->r->data) //RL型
return rl_change(root);
return root;
}
int main()
{
int i,j,n,m;
node *root =new node;
root=NULL;//這裏要初始化為NULL,不然build函數的if判斷不了
cin>>n;
for(i=0;i<n;i++){
int x;cin>>x;
root=build(root,x);
}
cout<<root->data;
return 0;
}
15.大数加减
c++
const int N=1e3+5;
int na[N],nb[N];
string add(string a,string b)
{
string ans;
int i;
int la=a.size(),lb=b.size();
memset(na,0,sizeof na);
memset(nb,0,sizeof nb);
for(i=0;i<la;i++){
na[la-i-1]=a[i]-'0';
}
for(i=0;i<lb;i++){
nb[lb-i-1]=b[i]-'0';
}
int maxl=max(la,lb);
for(i=0;i<maxl;i++){
na[i]+=nb[i];
na[i+1]+=na[i]/10;
na[i]%=10;
}
if(na[maxl]==0)maxl--;//去前置零
for(i=maxl;i>=0;i--)ans+=na[i]+'0';
return ans;
}
java
public class Main {
public static void main(String[] args) {
BigInteger n,m;//定义
Scanner scanner=new Scanner(System.in);
while(scanner.hasNext()){//多个输入
n=scanner.nextBigInteger();//输入
m=scanner.nextBigInteger();
n=n.add(m);
System.out.println(n);
}
}
}
16.最短路
dij:
typedef pair<int,int>pai;
vector<pai>vec[1005];
int dis[1005];
void dij(int u)
{
int i;
for(i=1;i<=n;i++)
{
dis[i]=INF;
}
dis[u]=0;
queue<int>qu;
qu.push(u);
while(!qu.empty())
{
int t=qu.front();
qu.pop();
for(i=0;i<vec[t].size();i++)
{
if(dis[vec[t][i].first]>dis[t]+vec[t][i].second)
{
dis[vec[t][i].first]=dis[t]+vec[t][i].second;
qu.push(vec[t][i].first);
}
}
}
}
堆优化 就改成优先队列 再加个visit数组 表示是否进过队列即可
ll dist[N],x;
bool vis[N];
struct qnode
{
int v;ll c;
qnode(int _v=0,ll _c=0):v(_v),c(_c) {}
bool operator <(const qnode &r)const
{
return c>r.c;
}
};
struct Edge
{
int v;ll cost;
Edge(int _v=0,ll _cost=0):v(_v),cost(_cost) {}
};
vector<Edge>E[N];
void add(int u,int v,ll w)
{
E[u].push_back(Edge(v,w));
E[v].push_back(Edge(u,w));
}
ll Dijkstra()
{
for(int i=0; i<=2*n+1; i++)dist[i]=1e15,vis[i]=false;
priority_queue<qnode>que;
while(!que.empty())que.pop();
dist[s]=0;
que.push(qnode(s,0));
qnode tmp;
while(!que.empty())
{
tmp=que.top();
que.pop();
int u=tmp.v;
if(vis[u])continue;
vis[u]=true;
for(int i=0; i<E[u].size(); i++)
{
int v=E[tmp.v][i].v;
ll cost=E[u][i].cost;
if(!vis[v]&&dist[v]>dist[u]+cost)
{
dist[v]=dist[u]+cost;
que.push(qnode(v,dist[v]));
}
}
}
return dist[t];
}
堆优化
View Code
floyd:
for(i=0;i<n;i++){
for(j=0;j<n;j++){
mp[i][j]=INF;
}
mp[i][i]=0;
}
//输入语句
for(k=0;k<n;k++){
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(mp[i][k]+mp[k][j]<mp[i][j])
mp[i][j]=mp[i][k]+mp[k][j];
}
}
}
spfa:
typedef pair<int,int>pai;
vector<pai>vec[1005];
const int INF=1e9;
int d[1005],inq[1005];//d数组 离源点距离;inq数组检查是否在队列里面
int cnt[1005];//入队次数
void spfa(int u)
{
int i;
memset(d,INF,sizeof d);
memset(inq,0,sizeof inq);
d[u]=0;
queue<int>qu;
qu.push(u);
inq[u]=1;
while(!qu.empty())
{
int t=qu.front();
qu.pop();
// cnt[t]++;
// if(cnt[t]==n+1){
// printf("有环\n");
// return;
// }
inq[t]=0;
for(i=0;i<vec[t].size();i++)
{
if(d[vec[t][i].first]>d[t]+vec[t][i].second)
{
d[vec[t][i].first]=d[t]+vec[t][i].second;
if(inq[vec[t][i].first]==1)continue;//先更新 再判断是否入队
qu.push(vec[t][i].first);
inq[vec[t][i].first]=1;
}
}
}
}
spfa(p);
cout<<d[q]<<endl;
17.结构体构造函数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pai;
const int INF=1e9;
const int N=1e6+5;
struct node{
int a,b;
node(){}
node(int x,int y){//构造函数
a=x,b=y;
}
};
int main()
{
int i,j,n,m,k;
queue<node>qu;
node no;//法一
no.a=3,no.b=4;
qu.push(no);
qu.push(node(3,4));//法二
return 0;
}
18.已知三点求三角形面积:|(x2-x1)(y3-y1)-(x3-x1)(y2-y1) | / 2
已知三边求三角形面积:(海伦公式)P=(a+b+c)/2 S=sqrt(P(P-a)(P-b)(P-c))
19.欧拉回路/欧拉路
无向图:欧拉回路-所有点都是偶点。欧拉路-只有两个积点,一个奇点是起点,另一个是终点,其他都是偶点(偶点表示偶数条边的点)
有向图:欧拉回路-所有点度数为0。欧拉路-只有一个点度数=1,另一个点度数=-1,其他=0(入度+1,出度-1,度数表示该点度数之和)
20.gcd可以--gcd(x,y)
也可以:
int gcd(int x,int y)
{
return y==0?x:gcd(y,x%y);
}
lcm则是x*y/gcd---防止爆精度,先除再乘
21.读懂题意很重要
https://pintia.cn/problem-sets/1320987234661515264/problems/1320988224353681413
所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方,同时还要保证每个居民点都在距离它一个不太远的范围内。
意思是:选中的垃圾点要求 到所有居民点的min距离要最大,同时max距离也要小于规定范围
https://pintia.cn/problem-sets/1320987234661515264/problems/1320988224366264321
二叉搜索树的最近公共祖先。给你先序,让你求任意两点的最近公共祖先
思路:我一开始建树,没必要,这样的话只能知道层序,不能知道父子关系,除非存一个父节点指针
后来 还是dfs 求下标,再直接判断
https://pintia.cn/problem-sets/1320987234661515264/problems/1320987934195933188
一个项目由若干个任务组成,任务之间有先后依赖顺序。项目经理需要设置一系列里程碑
在每个里程碑节点处检查任务的完成情况,并启动后续的任务。现给定一个项目中各个
任务之间的关系,请你计算出这个项目的最早完工时间。
看到任务想到拓扑,既然是拓扑,那么完成该节点的话就需要完成先该节点依赖的所有节点。
然后算出该节点完成的最短时间,也就是max时间,最后所有节点里求个max就是最早完工时间
22.零多项式含义:
零次多项式f(x)=a(a!=0)
零多项式即f(x)=0
零多项式和零次多项式都是常数多项式
findd=s.find("11");