#include
#define FF(a,b) for(int a=0;a
#define F(a,b) for(int a=1;a<=b;a++)
#define LEN 200
#define INF ((1<<30)-1)
#define bug(x) cout<<#x<<"="<
// 把INF定义为(INF+INF)还能保证不溢出的一个数
/*
INF+INF=2147483646
0x7FFFFFFF=2147483647
*/
using namespace std;
typedef long long ll;
const double pi=acos(-1);
double
输入:%lf
输出:%f
scanf
返回值解析:
返回正确读入的参数个数。
遇到文件结尾,返回EOF,也就是-1
安全的获取一行:fgets (buf, MAX, stdin)
printf
补前导0:%02d:总宽度为2,不足用0补
设置精度:%.2f保留两位小数
输入流输出流
关同步
std::ios::sync_with_stdio(false)
获取一行
cin.get(name,SIZE); //回车保留在输入队列中
cin.getline(name,SIZE); //回车被清除
设置输出精度
cout<<setprecision(2)<<a; //输出: 123.45
设置前导零:
cout<<setfill('0')<<setw(4)<<value<<endl;
原生实现lower_bound和upper_bound
https://www.luogu.org/problemnew/show/P3366
lower_bound
int l=0; //初始化 l ,为第一个合法地址
int r=10; //初始化 r , 地址的结束地址
int mid;
while(l<r) {
mid=(l+r)/2;
if(arr[mid]>=obj){
r=mid;
}else{
l=mid+1;
}
}
upper_bound
int l=0; //初始化 l ,为第一个合法地址
int r=10; //初始化 r , 地址的结束地址
int mid;
while(l<r) {
mid=(l+r)/2;
if(arr[mid]>obj){ //没有=符号是与上文算法唯一的区别
r=mid;
}else{
l=mid+1;
}
}
bool operator < (const Node& obj) const
{
return d<obj.d; //从小到大排序
}
int cmp(const Node&a,const Node&b){
return a.d<b.d;//从小到大排序
}
int cmp(Node& a,Node& b) {
if(a.name!=b.name) //最高优先级
return a.name<b.name;
else if(this.id!=o.id)
return a.id-b.id;
else
return a.credit-b.credit;
}
//---------------------堆优化----------------------------
struct cmp{
bool operator () (int a,int b){
return dist[a]>dist[b];
}
};
priority_queue<int,vector<int>,cmp> pq;
//---------------------堆优化----------------------------
在dijkstra使用
下文所有有注释的都是相对于非堆优化, 需要增删的内容
fill(dist,dist+LEN,MAX);
dist[s]=0;
pq.push(s); //优先队列入队初始化
while(!pq.empty()){ //优先队列非空
int u=pq.top(); //寻找最小的dist[u]
pq.pop();
if(vis[u]) continue; //寻找最小的dist[u]
vis[u]=1;
for(int i=0;i<N;i++) if(!vis[i]){
if(dist[u]+g[u][i]<=dist[i]){ //一定要包含等于符号!!!!
dist[i]=dist[u]+g[u][i];
pq.push(i); //优先队列入队
}
}
}
void print_via_ij(int i,int j){
if(via[i][j]!=-1){
int k=via[i][j];
cout<<k<<"->";
print_via_ij(k,j);
}else{
cout<<j<<"->";
}
}
void floyd(){
for(int i=0;i<N;i++){ //初始化
for(int j=0;j<N;j++){
if(g[i][j]==0) g[i][j]=INF;
via[i][j]=-1;
A[i][j]=g[i][j];
}
}
for(int k=0;k<N;k++){ //临时点
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
if(A[i][j]>(A[i][k]+A[k][j])){
A[i][j]=A[i][k]+A[k][j];
via[i][j]=k;
}
}
}
}
//输出0到各点距离
int v=0;
for(int i=1;i<N;i++){
cout<<v<<"->";
print_via_ij(v,i);
cout<<endl;
}
}
int N,M;
int dist[VN];
int pre[VN];
int vis[VN];
void dijkstra(int s){
fill(dist,dist+N,INF);
fill(pre,pre+N,-1);
dist[s]=0;
pq.push(s); //优先队列初始化
while(!pq.empty()){ //优先队列非空
int u=pq.top(); //找到最小u点
pq.pop();
if(vis[u]) continue;//找到最小u点
vis[u]=1; //找到最近点,加入S集
for(int i=head[u];~i;i=mp[i].next){ //链式前向星遍历
int to=mp[i].to; //链式前向星: u 的后继点 to
int w=mp[i].w; //链式前向星: u -> to 边权
if(!vis[to]){ //松弛
if(dist[to] >= dist[u]+w) { //s->to >= s->u->to,一定要包含等于符号
dist[to] = dist[u] + w;
pre[to]=u;
pq.push(to);
}
}
}
}
}
int pathc[VN]; //最短路条数
void dijkstra(int s,int e){
pathc[s]=1; //初始化源点最短路条数
if(!vis[to]){ //松弛
if(dist[to] > dist[u]+w) { //s->to > s->u->to
pathc[to] = pathc[u];
//其余公操作
}else if(dist[to]==dist[u]+w){
pathc[to] += pathc[u];
//其余公操作
}
}
在有多条最短路的情况下, 寻找点权途经点权最大的最短路
int vw[VN]; //点权 vertex weight
int by_vw[VN]; //途经点权 bypass vertex weight
void dijkstra(int s,int e){
by_vw[s]=vw[s];//初始化源点途经点权
...................
if(!vis[to]){ //松弛
if(dist[to] > dist[u]+w) { //s->to > s->u->to
by_vw[to]=by_vw[u]+vw[to];
//其余公操作
}else if(dist[to]==dist[u]+w){
if(by_vw[u]+vw[to] > by_vw[to]){
by_vw[to]=by_vw[u]+vw[to];
}
}
}
//--------------------------并查集-----------------------------
int fa[LEN];
int init(){
int i;
FF(i,LEN) fa[i]=i;
}
int findFa(int x){
if(x==fa[x]) return x;
int r=x;
while(r!=fa[r]){//找到根节点
r=fa[r];
}
int t=x;
while(x!=fa[x]){//路径压缩
t=fa[x];
fa[x]=r;
x=t;
}
return r;
}
void Union(int a,int b){
int pa=findFa(a);
int pb=findFa(b);
fa[pa]=pb;
}
//--------------------------边表-----------------------------
typedef struct Edge{//边表
int u,v,w;//两点和边权
//按照边权对边表进行排序
bool operator < (const Edge& obj) const
{
return w<obj.w; //从小到大排序
}
}Edge;
Edge edge[200010];
init(); //一定要初始化,不然拉闸
int cnt=0,mst=0;
FF(i,M){
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
}
sort(edge,edge+M);
FF(i,M){
Edge &e=edge[i];
//Union操作
int pa=findFa(e.u);
int pb=findFa(e.v);
if(pa==pb)
continue;
fa[pa]=pb;
//更新MST
mst+=e.w;
cnt++;
}
if(cnt==N-1){
printf("%d\n",mst);
}else{
printf("orz\n");
}
int fa[LEN];
int init(){
int i;
FF(i,LEN) fa[i]=i;
}
int findFa(int x){
if(x==fa[x]) return x;
int r=x;
while(r!=fa[r]){//找到根节点
r=fa[r];
}
int t=x;
while(x!=fa[x]){//路径压缩
t=fa[x];
fa[x]=r;
x=t;
}
return r;
}
void Union(int a,int b){
int pa=findFa(a);
int pb=findFa(b);
fa[pa]=pb;
}
https://www.cnblogs.com/TQCAI/p/8546737.html
Node* build_tree(int ps,int pe,int is,int ie){//Node* root=build_tree(0,n-1,0,n-1);
if(ps>pe) return NULL;
if(ps==pe) return new Node(in[is]);
int i=is;
while(i<=ie && in[i]!=pre[ps]) i++;
Node * node=new Node(in[i]);
int dLeft=i-is; //左侧元素数量
node->l=build_tree(ps+1,ps+dLeft,is,is+dLeft-1);
node->r=build_tree(ps+dLeft+1,pe,i+1,ie);
return node;
}
Node* build_tree(int ps,int pe,int is,int ie){//Node* root=build_tree(0,n-1,0,n-1);
if(ps>pe) return NULL;
if(ps==pe) return new Node(in[is]);
int i=is;
while(i<=ie && in[i]!=post[pe]) i++;
Node * node=new Node(in[i]);
int dLeft=i-is; //左侧元素数量
node->l=build_tree(ps,ps+dLeft-1,is,is+dLeft-1);
node->r=build_tree(ps+dLeft,pe-1,i+1,ie);
return node;
}
//caution: should using initialize code: " t=0; "
//pre + in -> post
// pre_start pre_end in_start in_end
void setPost(int ps,int pe,int is,int ie){
if(ps>pe)return;//null
if(ps==pe){
post[t++]=pre[ps];
}else{
//find the elem is the pair of preOrder (ps)
int i=is;
while(in[i]!=pre[ps] && i<ie) i++;//redirect
//left
setPost(ps+1, ps+i-is, is, i-1);
//right
setPost(ps+i-is+1, pe, i+1, ie);
//root
post[t++]=pre[ps];
}
}
//caution: should using initialize code: " t=0; "
//post + in -> pre
// post_start post_end in_start in_end
void setPre(int ps,int pe,int is,int ie){
if(ps>pe)return;//null
if(ps==pe){
pre[t++]=post[ps];
}else{
//find the elem is the pair of preOrder (ps)
int i=is;
while(in[i]!=post[pe] && i<ie) i++;//redirect
//root
pre[t++]=post[pe];
//left
setPre(ps, ps+i-is-1, is, i-1);
//right
setPre(ps+i-is, pe-1, i+1, ie);
}
}
void setIn(int preS,int preE,int postS,int postE){
if(preS>preE) return;
if(preS==preE){
in[t++]=pre[preS];
return;
}
int i=postS;
while(i<=postE-1 && post[i]!=pre[preS+1]) i++;
int ln=i-postS+1; //left_num
if(i==postE-1){ //more than one condition
yes=0;
//默认找到的结点都为【左结点】。(如果想设置为“右结点”,可以改变setIn递归函数的位置)
setIn(preS+1,preS+ln,postS,postS+ln-1);
in[t++]=pre[preS];
return;
}
setIn(preS+1,preS+ln,postS,postS+ln-1);
in[t++]=pre[preS];
setIn(preS+ln+1,preE,postS+ln,postE-1);
}
int cnt;
void calc(int preS,int preE,int postS,int postE){
if(preS>=preE) return;
int i=postS;
while(i<=postE-1 && post[i]!=pre[preS+1]) i++;
int ln=i-postS+1; //left_num
if(i==postE-1) cnt++;
calc(preS+1,preS+ln,postS,postS+ln-1);
calc(preS+ln+1,preE,postS+ln,postE-1);
}
最后结果为pow(2,cnt)种结果
typedef struct Node{
int d;
struct Node* l;
struct Node* r;
Node(int d):d(d){
l=r=NULL;
}
};
Node * root;
map<int,int> num2index; //求一个数在中序中的索引
int layer[LEN];
int in[LEN];
核心代码
//主程序段调用
for(int i=1;i<=n;i++){ //循环变量 i 遍历整个 layer 数组
j=1;
while(j<=n && in[j]!=layer[i]) j++; //找到in[j]==layer[i]
num2index[in[j]]=j; //这个数在中序中的索引
build_tree(root,j);
}
//建树函数
void build_tree(Node* & root,int i){// index of in
if(!root){
root=new Node(in[i]);
return;
}
int ri=num2index[root->d]; //root_index;
if(i<ri) build_tree(root->l,i);
else build_tree(root->r,i);
}
https://www.cnblogs.com/TQCAI/p/8538920.html
数据结构定义
int arr[100];
typedef struct Node{
int d,l,r,i;
Node(int d=0):d(d){
l=-1;
r=-1;
}
bool operator < (const Node& obj) const
{
return d>obj.d; //因为要装入到大根堆的优先队列中
}
}Node;
Node nodes[100];//静态结点
初始化
int i,n=0;
while(~scanf("%d",&i)){
nodes[n]=Node(i);
nodes[n].i=n; //类似并查集,如果没有父结点,父结点就是自己
pq.push(nodes[n]);
n++;
}
建立Huffman树
while(pq.size()>1){ //最后只剩下一个结点
//从优先队列中拿出两个最小的结点
if(pq.empty())
break;
Node a=pq.top();
pq.pop();
if(pq.empty())
break;
Node b=pq.top();
pq.pop();
//构造一个新的结点
Node c(a.d+b.d);
c.l=a.i;
c.r=b.i;
nodes[n]=c; //放到新的静态区域中,并对n更新
c.i=n;
n++;
//把新的结点放入优先队列中
pq.push(c);
}
更新:区间加,查询:区间和
https://www.luogu.org/problemnew/show/P3372
#define LSON LS(p),l,mid
#define RSON RS(p),mid+1,r
#define LS(x) x<<1
#define RS(x) x<<1|1
#define MS ll mid=(l+r)>>1
ll a[LEN];
ll tree[LEN*4]; //线段树
ll lazy[LEN*4]; //lazy优化
inline void push_up(ll p){
tree[p]=tree[LS(p)]+tree[RS(p)];
}
void build(ll p, ll l, ll r){
lazy[p]=0;
if(l==r){
tree[p]=a[l];
return;
}
MS;
build(LSON);
build(RSON);
push_up(p);
}
inline void f(ll p,ll l,ll r,ll d){
lazy[p]+=d;
tree[p]+=d*(r-l+1);
}
inline void push_down(ll p,ll l,ll r){
ll mid=(l+r)>>1;
f(LSON,lazy[p]);
f(RSON,lazy[p]);
lazy[p]=0;
}
//update(nl,nr,1,1,N,d)
inline void update(ll nl,ll nr,/*固定域*/ ll p, ll l, ll r,/*查找域*/ ll d){
if(nl<=l && r<=nr){
tree[p]+=d*(r-l+1);
lazy[p]+=d;
return;
}
push_down(p,l,r);
MS;
if(nl<=mid)
update(nl,nr,LSON,d);
if(mid<nr) // (mid+1)<=nr
update(nl,nr,RSON,d);
push_up(p);
}
//query(nl,nr,1,1,N)
ll query(ll nl,ll nr,/*固定域*/ ll p, ll l, ll r/*查找域*/){
ll res=0; //add
if(nl<=l && r<=nr)
return tree[p]; //modify
push_down(p,l,r);
MS;
if(nl<=mid)
res+=query(nl,nr,LSON); //modify
if(mid<nr)
res+=query(nl,nr,RSON); //modify
return res; //add
}
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int dir[8][2];
int n;
void build_dir()
{
int k=0;
FF(i,3)FF(j,3){
if(i==1 && j==1) continue;
dir[k][0]=i-1;
dir[k][1]=j-1;
k++;
}
}
void dfs(int s){//当进入dfs(s)时,0~s-1的状态都已经完成
//退出区
if(s==e){ //终态。也可以在退出区剪枝
return; //一定要有返回
}
//入栈区
path.push_back(s);
vis[s]=1;
//遍历区
for(i){
dfs(i);
}
//出栈区
vis[s]=0;
path.pop_back();
}
//调用
vis[s]=1;//注意,如果初态不同,可能还会有循环
dfs(s);
vis[s]=0;
//dfs
void dfs(int s){
if(s==e){ //终态判断也可以写在for内
return; //一定要有返回
}
for(i){
path.push_back(i);
vis[i]=1;
dfs(i);
vis[i]=0;
path.pop_back();
}
}
void backtrack(int t) { //坑: 第一个结果并不是字典序最小结果
if (t > N){
//终态
}else
for (int i = t; i<=N; i++){
swap(x[t], x[i]);
if(/*剪枝条件 && 限制条件*/) backtrack(t+1);
swap(x[t], x[i]);
}
}
自带的全排列
do{
//终态
}while(next_permutation(arr,arr+n)); //n!
void bfs(){
queue<node> q;
q.push(S);
vis[S]=1;//入队标记
bool isFind=false;//终态标记
while(!q.empty()){
int sz=q.size();
while(sz--){ //方便计算层数
node u=q.front();
q.pop();
if(u==E){ //终态
isFind=true;
goto END;
}
FF(i,N){ //对于N种情况进行分析
if(!vis[i]){ //入队判断
vis[i]=1;
q.push(Node[i]); //入队标记
}
}
}
step++; //bfs层数
}
END: //cpp用goto跳出多重循环,Java有其他法
}
排列序列A(n,m)
int a[LEN]; //排列前的序列
int vis[LEN],cur[LEN]; //完成一次排列后形成的序列
void permutations(int t,int n,int m){//A(n,m)
if(t>=m){ //达到循环上限
for(int i=0;i<m;i++) //输出一次排列后的序列
printf("%d ",cur[i]);
printf("\n");
return;
}else{
for(int i=0;i<n;i++)if(!vis[i]){
vis[i]=1;
cur[t]=a[i];
permutations(t+1,n,m);
vis[i]=0;
}
}
}
//调用
permutations(0,n,m);
笛卡尔积P(n,m)
string a="1234";//递归前
vector<string> ans;//递归结果
string ch2str(char fuck){
char fuckYou[2]={0};
fuckYou[0]=fuck;
return fuckYou;
}
void product(int t,int n,int m){//P(n,m)
if(t>=m){//达到循环上限
for(int i=0;i<ans.size();i++)
printf("%s\n",ans[i].c_str());
return;
}else{
vector<string> tmp;
int sz=ans.size();
if(sz){
for(int i=0;i<n;i++){
for(int j=0;j<sz;j++){
tmp.push_back(ans[j]+a[i]);
}
}
}else{
for(int i=0;i<n;i++){
tmp.push_back(ch2str(a[i]));
}
}
ans=tmp;
product(t+1,n,m);
}
}
C语言字符串函数
//拷贝
char *strcpy(char *dest, const char *src)
//比较
int strcmp(const char *str1, const char *str2)
如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str2 小于 str1。
如果返回值 = 0,则表示 str1 等于 str2。
char *strncpy(char *dest, const char *src, size_t n)
//->实例
char src[10]="1234567";
char dest[10];
int start=2;
int length=3;
strncpy(dest,src+start,length);
dest[length]=0;//制作终止符
memset(void *s,int ch,size_t n);
注意:
对于在源程序段声明的数组,可以用sizeof直接获得字节大小。对于函数内声明的数组不行。
只能对字节进行赋值,常用的有0和1 。
对于数组a,对于区间[0,N),进行求和,之后加上0
int sum=accumulate(a,a+N,0);
distance求迭代器的下标
distance(s.begin(),it)
一维数组: fill(a,a+length,value);
二维数组:
FF(i,LEN)
fill(dp[i],dp[i]+LEN,0);
一种用法是判断容器内是否存在某一元素
count(a, a+length, value)
count_if(a, a+length, condition_function)
int*p=search(seq,seq+5,sub,sub+3);
seq中是否有n个value
int*p=search_n(seq,seq+8,n,value);
数组arr为连续序列,重复的元素都相邻。使用下面语句后,去重+长度更新
n=unique(arr,arr+n)-arr;
用法1
//将数组myints中的七个元素复制到myvector容器中
copy ( myints, myints+7, myvector.begin() );//调用这行代码之前,必须用 myvector.resize(7)
用法2 数组平移
copy(arr+1,arr+9+1,arr);//把长度为9的数组向左平移1位
for_each对于每个迭代器执行指定函数
// 3 for_each
void fun(map<int,string>::reference a) //不要少了reference,不然会报错。
{
a.second+="_suffix"; //a是引用对象。
cout<<a.first<<" "<<a.second<<endl;
}
for_each(m.begin(),m.end(),fun);
void fun1(int & p){ //回调函数的参数同样也是引用类型
p++;
}
bool ans=equal(A,A+LEN,B);
pair<int*,int*>ans=mismatch(A,A+LEN,B);
向左移动n位
rotate(A,A+n,A+LEN);
向右移动n位
rotate(A,A+LEN-n,A+LEN);
swap_ranges(A,A+5,B);
// 把要删除的元素移动到容器末尾
it=remove(v.begin(),v.end(),removedValue) //it为末尾删除区的第一个元素
// 真正意义上的删除
v.erase(remove(v.begin(),v.end(),removedValue),v.end());
transform对容器中的序列套接一个函数,把结果放到一个容器
transform(A,A+LEN,B,add);
replace把序列中的某个值替换为另一个值
replace(std::begin(data), std::end(data), pre, after);
string(int n,char c); //用n个字符c初始化
string substr(int pos=0, int n=npos) const; //返回由pos开始的n个字符组成的子字符串
注意! find函数如果查找不到,就返回string::npos
int find(char c,int pos=0) const; //从pos开始查找字符c在当前字符串的位置
int find(const char *s, int pos=0) const; //从pos开始查找字符串s在当前字符串的位置
int find(const string &s, int pos=0) const; //从pos开始查找字符串s在当前字符串中的位置
find函数如果查找不到,就返回 string::npos
int rfind(char c, int pos=npos) const; //从pos开始从后向前查找字符c在当前字符串中的位置
int rfind(const char *s, int pos=npos) const;
int rfind(const string &s, int pos=npos) const;
//rfind是反向查找的意思,如果查找不到, 返回npos
string &replace(int pos, int n, const char *s);//删除从pos开始的n个字符,然后在pos处插入串s
string &replace(int pos, int n, const string &s); //删除从pos开始的n个字符,然后在pos处插入串s
void swap(string &s2); //交换当前字符串与s2的值
string &insert(int pos, const char *s);
string &insert(int pos, const string &s);
//前两个函数在pos位置插入字符串s
string &insert(int pos, int n, char c); //在pos位置 插入n个字符c
string &erase(int pos=0, int n=npos); //删除pos开始的n个字符,返回修改后的字符串
注意string的erase与其他容器的erase不同。其他容器的erase删除迭代器,返回删除元素的第一个后级元素
transform(s.begin(), s.end(), s.begin(), ::toupper);//转大写
transform(s.begin(), s.end(), s.begin(), ::tolower);//转小写
‘0’=48 ‘a’=97 ‘A’= 65
void insertStr(string &str,const string &obj,int pos=0){
str.replace(pos,0,obj);
}
bool replaceAll(string &str,const string &a,const string &b){
int al=a.length();
int bl=b.length();
int pos,pre=0;
bool isFind=false;
while((pos=str.find(a,pre))!=string::npos){
str.replace(pos,al,b);
pre=pos+bl;
isFind=true
}
return isFind;
}
void split(string s,char token,vector<string>& v){
int n=s.length();
string t;
FF(i,n){
char c=s[i];
if(c!=token)
t+=c;
else{
v.push_back(t);
t="";
}
}
v.push_back(t);
}
void split(string s,string token,vector<string>& v){
int n=s.length();
int m=token.length();
string t;
int i=0;
while(i+m<=n){
int step=1;
char c=s[i];
if(s.substr(i,m)!=token)
t+=c;
else{
v.push_back(t);
t="";
step=m;
}
i+=step;
}
v.push_back(t);
}
基本操作
入队:push()
出队:pop()
队顶:top()
pq默认为大根堆(见严蔚敏的大根堆和堆排序),但是如果我们想用小根堆:
priority_queue<int,vector<int>,greater<int> > pq;
结构体小根堆
//根据d的值有小到大
typedef struct Node{
int d;
bool operator < (const Node& obj) const
{
return d>obj.d; //注意
}
}Node;
priority_queue<Node> pq;
struct cmp{
bool operator () (int a,int b){
return dist[a]>dist[b];
}
};
priority_queue<int,vector<int>,cmp> pq;
set:红黑树实现
multiset:多值集合,但能动态排序
初始化:
int num[]={1,2,3};
multiset<int> s(num,num+3);
插入:insert()
计数:count() 也可以判断某个item存在与否
清空:clear()
查找:it=find(s.begin(),s.end(),v); 或者it=s.find(v)
获取下标:distance(s.begin(),it)
查找失败:it==s.end()
[a,b)
s.lower_bound(v) s.upper_bound(v)
删除:
s.erase(it)或s.erase(it_begin,it_end)
注意,set的迭代器没有实现+操作符,所以只能循环使用++或–来对下标进行定位
遍历:
multiset<int>::iterator it=s.begin();
while(it!=s.end()){
printf("%d",*it);
it++;
if(it!=s.end())
printf(" ");
}
改为从大到小排序
使用STL自带重载
set
struct cmp{
bool operator() (const int& a,const int& b) const
{
return a>b;
}
};
set<int,cmp> s;
结构体放入
typedef struct Node{
int d;
Node(int d):d(d){}
bool operator < (const Node& obj) const
{
return d<obj.d; //从小到大排序
}
}Node;
while(it!=v.end()){
if(*it==3){//满足了某一条件,则删除
it=v.erase(it);
}else{//不满足,自增
it++;
}
}
https://blog.csdn.net/TQCAI666/article/details/88692096
typedef struct Node{//运算结点,记录数字或运算符号
bool isop;
char op;
int num;
Node(){}
Node(int d){
num=d;
isop=0;
}
Node(char op_){
op=op_;
isop=1;
}
void output(){
if(isop) cout<<op;
else cout<<num;
}
}Node;
int getPriority(char op){
switch(op){
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return 0;
}
}
vector<Node> yieldPostOrderExpress(vector<Node> &in){
vector<Node> post;
Node ops[LEN];
int top=-1;//栈顶指针
FF(i,in.size()){
Node u=in[i];
if(u.isop){
if(u.op=='('){
ops[++top]=u;//入栈
}else if(u.op==')'){
while(top>=0){
Node p=ops[top--];
if(p.op=='('){
break;
}else{
post.push_back(p);
}
}
}else{
while(top>=0 && getPriority(u.op) <= getPriority(ops[top].op)){
post.push_back(ops[top--]);//持续出栈直到满足优先级
}
ops[++top]=u;//入栈
}
}else{
post.push_back(u);
}
}
//处理剩下的栈
while(top>=0){
post.push_back(ops[top--]);
}
return post;
}
Node operate(Node &a,Node& b,char op){
int v;
switch(op){
case '+':
v=a.num+b.num;
break;
case '-':
v=a.num-b.num;
break;
case '*':
v=a.num*b.num;
break;
case '/':
v=a.num/b.num;
break;
}
return Node(v);
}
int calcPostOrderExpress(vector<Node>& post){
Node s[LEN];
int top=-1;
FF(i,post.size()){
Node& u=post[i];
if(u.isop){
Node a=s[top--];
Node b=s[top--];
Node ans=operate(a,b,u.op);
s[++top]=ans;
}else{
s[++top]=u;
}
}
return s[0].num;
}
实值转二进制序列
string getBinarySequence(int num){
string ans="";
while(num){
if(num&1){
ans="1"+ans;
}else{
ans="0"+ans;
}
num>>=1;
}
return ans;
}
R进制序列转实值
int getTrueValue(int r,string seq){//radix sequence
int n=seq.size();
int base=1;
int ans=0;
for(int i=n-1;i>=0;i--){
int v=seq[i]-'0';
ans+=v*base;
base*=r;
}
return ans;
}
记忆化搜索计算组合数
int C[50][50];
int C_(int n,int m){
if(C[n][m]) return C[n][m];
if(m==0){
C[n][m]=1;
return C[n][m];
}
if(m==n){
C[n][m]=1;
return C[n][m];
}
else{
C[n][m]=C_(n-1,m-1)+C_(n-1,m);
return C[n][m];
}
}
ll quickPower(ll a,ll b){
ll ans=1,base=a;
while(b>0){
if(b&1)
ans*=base;
base*=base;
b>>=1;
}
return ans;
}
ll quickPowerMod(ll a,ll b,ll m){
ll ans=1,base=a;
while(b>0){
if(b&1){
ans*=base;
ans%=m;
}
base*=base;
base%=m;
b>>=1;
}
return ans%m;
}
hp ans("1");
hp base("2"); //2^p
while(P>0){
if(P&1)
ans=multiplyh(ans,base);
base= multiplyh(base,base);
P>>=1;
}
矩阵乘法
matrix* multi(matrix& A, matrix& B){
matrix* C=new matrix;
C->row=A.row;
C->col=B.col;
for(int i=0;i<A.row;i++)
for(int j=0;j<B.col;j++)
for(int k=0;k<A.col;k++)
C->m[i][j]+=A.m[i][k]*B.m[k][j];
return C;
}
矩阵快速幂
matrix quickPower(matrix& A,int p){ //A^p
int n=A.col;
//得到单位阵
matrix ans(n,n);//ans=E
FF(i,n)
FF(j,n)
if(i==j)
ans.m[i][j]=1;
else
ans.m[i][j]=0;
//开始快速幂
matrix base=A;
while(p){
if(p&1)
ans=*multi(ans,base);
base=*multi(base,base);
p>>=1;
}
return ans;
}
int gcd(int a,int b){
while( b != 0){
int t = a % b;
a = b;
b = t;
}
return a;
}
素数判断
bool isPrime(int x){
if(x<=1) return 0;
for(int i=2;i<=sqrt(x);i++){
if(x%i==0) return 0;
}
return 1;
}
#define MAXN 100005 //素数的最多个数
#define MAXL 1299710 //要求的最大素数
//实际操作中,只需要控制MAXL的长度,MAXN开的足够大即可
int prime[MAXN];//素数表
int check[MAXL];//如果n是素数,则check[n]=0,否则check[n]=1
void EulerSieveMethod(){
int tot = 0;
memset(check, 0, sizeof(check));
for(int i=2;i<MAXL;i++){
if(check[i]==0){//素数
prime[tot++]=i;
}
for(int j=0;j<tot;j++){
int v=i*prime[j];
if(v>MAXL) break;
check[v]=1;
if(i%prime[j]==0)//有点没搞明白
break;
}
}
}
01背包
https://www.luogu.org/problemnew/show/P1048
对于刚好装满问题
采用-INF对f数组进行初始化
fill(f,f+FN,-INF);
需要注意的是,INF应该采取最大的安全值,例如:#define INF ((1<<30)-1)
f[0]初始化为0
对结果进行判断
if(ans<0)
puts("NO");
else
printf("%d\n",ans);
原生方法
for(int i = 1; i <= N; i++){ //i代表物品
for(int j = 0; j <= M; j++){ //j代表当前背包容量上限
if(j>=w[i]){ //当前物品能放入
f[i][j]=max(f[i-1][j], //不放
f[i-1][j-w[i]]+v[i]); //放
}else{
f[i][j]=f[i-1][j];
}
}
}
printf("%d", f[N][M]);
滚动数组优化
for(int i=1;i<=N;i++){
for(int c=M;c>=w[i];c--){
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
printf("%d\n",f[M]);
完全背包
http://nyoj.top/problem/311
滚动数组优化
for(int i=1;i<=N;i++){
for(int c=w[i];c<=M;c++){
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
最长不下降子序列LIS
N2复杂度
void DP_n2(){
int p; //LIS 结束的下标
int ans=0;
F(i,n){
dp[i]=1; //初始化
F(j,i-1){
if(a[j]<a[i])
dp[i]=max(dp[i],dp[j]+1);
}
if(dp[i]>ans){ //更新最优解
ans=dp[i];
p=i;
}
}
}
分析:根据DP数组的线性递增顺序就能找到所有的LIS序列
ans=5 p=11
//序列 :
1 3 7 6 8 5 3 2 7 2 9
//DP数组 :
1 2 3 3 4 3 2 2 4 2 5
Nlog2N复杂度
不严格递增(不下降)
void DP_nLogn1(){
int top=0;
F(i,n){
if(top==0 || a[i]>=dp[top-1])
dp[top++]=a[i];
else{
int pos=upper_bound(dp,dp+top,a[i])-dp;
dp[pos]=a[i];
}
}
}
严格递增
void DP_nLogn2(){
int top=0;
F(i,n){
if(top==0 || a[i]>dp[top-1])
dp[top++]=a[i];
else{
int pos=lower_bound(dp,dp+top,a[i])-dp;
dp[pos]=a[i];
}
}
}
void LCS(){
F(i,N){
F(j,M){
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]);
}
}
}
最大子段和
int i,p=0,ans=-MAX,t,n;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d",&t);
p+=t;
ans=max(ans,p);
if(p<0) p=0; //说明当前的t是负数, 从下个t开始初始化
}
printf("%d\n",ans);
加分二叉树
F(i,N){
cin>>f[i][i];
f[i][i-1]=1; //空结点为0
root[i][i]=i;
}
f[N+1][N]=1;
for(int d=1;d<N;d++){//间隔
for(int i=1;i+d<=N;i++){//开始
int j=i+d;//结束
root[i][j]=i;
f[i][j]=f[i][i]+f[i+1][j];
for(int k=i+1;k<=j;k++){ //分割
int tmp_fij=f[k][k]+f[i][k-1]*f[k+1][j];
if(tmp_fij>f[i][j]){
f[i][j]=tmp_fij;
root[i][j]=k;
}
}
}
}
cout<<f[1][N]<<endl;
同样用到了区间DP的思想,通过逐渐增大排查范围,无后效性
char buf[LEN];
int dp[LEN][LEN];
int main()
{
fgets(buf,LEN,stdin);
int N=strlen(buf);
//初始化。1表示合法
FF(i,N) dp[i][i]=1;
int ans=0;
FF(i,N-1)
if(buf[i]==buf[i+1])
dp[i][i+1]=1;
for(int v=2;v<N;v++){//v表示间隔
for(int i=0;i+v<N;i++){//i表示开始下标
int j=i+v;
if(buf[i]==buf[j] && dp[i+1][j-1]==1){//判定为合法
dp[i][j]=1;
ans=max(ans,v);
}
}
}
printf("%d",ans+1);
return 0;
}
归并排序求逆序对
tmp[LEN],a[LEN];
ans=0;
arr[LEN];
void merge(ll s,ll mid,ll e){
i=0,a=s,b=mid+1;
while(a<=mid && b<=e){
if(arr[a]<=arr[b]){ //巨坑,<=
tmp[i++]=arr[a++];
}else{
tmp[i++]=arr[b++];
ans+=mid-a+1;
}
}
while(a<=mid) tmp[i++]=arr[a++];
while(b<=e) tmp[i++]=arr[b++];
FF(j,i) arr[s+j]=tmp[j];
}
void mergeSort(ll s,ll e){
if(s<e){ //能够被划为。如果只有一个数就不能被划分
ll mid=(s+e) /2;
mergeSort(s,mid);
mergeSort(mid+1,e);
merge(s,mid,e);
}
}
假设有N级台阶,一个人一次可以走[1,K]级,问一共有多少种走法
相当于一次可以走1、 2步的斐波那契问题的推广
f[0]=1;//初始化第一步
for(int i=1;i<=N;i++){//每一级台阶
for(int j=1;j<=K && i-j>=0 ;j++){//走j步,j∈[1,K]
f[i]+=f[i-j];
}
}
cout<<f[N];
有N个人,其中一个人可以从他的左边或者右边接到球。游戏开始,某人发球,求进行M次游戏后,球重新回到他的手中的传球方法数。
实则为dp
状态转移:f[i][k]=f[i-1][k-1]+f[i+1][k-1],(i=1或n时,需单独处理)
f[1][0]=1;//fij表示在第j轮,球传到i手中的方法数。
for(int i=1;i<=m;i++)//传 m 次
{
f[1][i]=f[2][i-1]+f[n][i-1]; //第一个
f[n][i]=f[1][i-1]+f[n-1][i-1]; //最后一个
for(int j=2;j<n;j++) //中间
f[j][i]=f[j-1][i-1]+f[j+1][i-1];
}//注意第一个人和最后一个人的单独处理
printf("%d",f[1][m]);
原文链接:https://blog.csdn.net/weixin_44312186/article/details/88870507