inline ll read() { int x=0,f=0; char ch=getchar(); while(!isdigit(ch)) f|=(ch=='-'),ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; }
① 位运算乘除html
② for 卡常node
for(register int i(1); i<=n; ++i) {}
③ 短函数前加 inline
卡常git
④ 判断奇偶数组
if(a%2==0) 能够转化成 if((a&1)==0)
⑤ 取模用 &
数据结构
x=667%4; 能够转化成 x=667&(4-1); x=667%32; 能够转化成 x=667&(32-1);
⑥ 正负转换用位运算函数
i=-1; 能够转换成 i=~i+1; 或 i=(i^-1)+1;
⑦ 取绝对值spa
k=abs(x); 能够转换成 k=(x^(x>>31))-(x >> 31);
静态查询区间最值。code
ll f[100001][20]; ll n,m,a[100001]; void ST_make(){ for(int i=1;i<=n;++i) f[i][0]=a[i]; ll t=log(n)/log(2)+1; for(int j=1;j<t;++j) for(int i=1;i<=n-(1<<j)+1;++i) f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); } ll ST_q(ll l,ll r) { ll k=log(r-l+1)/log(2); return max(f[l][k],f[r-(1<<k)+1][k]); } int main() { n=read(); m=read(); for(int i=1;i<=n;++i) a[i]=read(); ST_make(); for(int i=1;i<=m;++i) { ll l=read(),r=read(); printf("%lld\n",ST_q(l,r)); } return 0; }
给定一个整数 \(n\) ,求出 $[2,n] $ 之间的全部素数。htm
思路:prime
数组存放已经筛出的素数, \(m\) 表明素数个数(也就是说遍历时从 \(1\) 遍历到 \(m\) 便可),v
数组表明有没有被标记,避免重复筛。blog
int v[maxn],prime[maxn],n,k,t,m; void primes(int n) { memset(v,0,sizeof(v));//清空标记数组 m=0;//质数个数 for(int i=2;i<=n;i++) { if(!v[i])//未被标记,i为质数 v[i]=i, prime[++m]=i; //记录 for(int j=1;j<=m;j++) { if(prime[j]>v[i]||prime[j]>n/i) break;//i有更小的质因子,或者超出n的范围 v[i*prime[j]]=prime[j];//prime[j]为合数 i*prime[j]的最小质因子 } } } int main() { scanf("%d",&n); primes(n); for(int i=1;i<=m;++i) printf("%d\n",prime[i]); }
① 标准
inline int gcd(int a,int b) { int r; while(b>0) { r=a%b; a=b; b=r; } return a; }
② 三目
inline int gcd(int a,int b) { return b>0 ? gcd(b,a%b):a; }
③ 位运算
inline int gcd(int a,int b) //a,b不能为0 { while(b^=a^=b^=a%=b); return a; }
④ 展转相除法
inline int gcd(int a,int b) { if(a%b==0) return b; else return (gcd(b,a%b)); }
⑤ 展转相减法
int gcd(int a,int b) { if(a==b)return a; return a>b?gcd(a-b,b):gcd(b-a,a); }
⑥ 外挂(考试禁止)
#include <algorithm> inline int gcd(int a,int b) { return __gcd(a,b); //其实能够在主函数里直接用这个 }
给定三个整数 \(a,n,mod\) ,求 \(a \times n ~\%~mod\) 的值。
inline int mult_mod(int a,int n,int mod) { int ans=0; while(n>0) { if(n&1) ans=(ans+a)%mod; a = (a+a)%mod; n >>= 1; } return ans; }
这个东西好像没有必要的样子,貌似只须要 \((a~\%~mod)×(n~\%~mod)~\%~mod\) 便可。
给定三个整数 \(a,n,mod\) ,求 \(a^n~\%~mod\) 的值。
int ksm(int a,int n,int mod) { if(a==1 || n==0 ) { if(mod==1) return 0; return 1; } int m=a,ans=1; while(n>0) { if(n&1) { ans*=m; ans%=mod; } m*=m; m%=mod; n>>=1; } return ans; }
求一个序列的最长上升子序列个数。
本程序采用边读边处理 + 二分法。
ll f[maxn], ans = 1; //注意答案个数初始化为1 int main() { ll n = read(); for (int i = 1; i <= n; ++i) { int x = read(); if (i == 1) { f[1] = x; continue; } int l = 1, r = ans, mid; while (l <= r) { mid = (l + r) >> 1; if (x <= f[mid]) r = mid - 1; else l = mid + 1; } f[l] = x; if (l > ans) ++ans; } printf("%lld\n", ans); return 0; }
使用前提:数列为有序数列。
//查找范围:[ begin , end ) ,左闭右开区间。 *lower_bound(begin,end,num); //返回第一个 >= num 的数的数值 lower_bound(begin,end,num)-begin; // 返回下标 实际操做: int a[100]={0,1,3,5,7,9,10}; // 下标:0 1 2 3 4 5 6 int main() { int x=lower_bound(a+1,a+6+1,6)-a; //输出下标 int y=*lower_bound(a+1,a+6+1,6); //输出值 printf("%d %d",x,y); return 0; } 输出结果:4 7
结构体内使用 lower_bound 须要重载,下面咱们主要对结构体中的 \(a\) 进行操做。
struct node //开结构体 { int a, id; //定义结构体内的两个变量 node() {} node(int x, int y) : a(x), id(y) {} bool operator < (const node t) const //重载 { return a < t.a; } }t[1001]; bool cmp(node x,node y) //快排 cmp 比较函数 { if(x.a < y.a) return 1; //结构体内按 a 由小到大排序。 return 0; } int main() { int n=read(); //数列中数的个数 for(int i=1;i<=n;++i){ t[i].a=read(); //读入数列 t[i].id=i; } sort(t+1,t+n+1,cmp); //按小到大排序 int x,xiabiao,ans; x=read(); //须要查找的数字 xiabiao=lower_bound(t+1,t+n+1,node(x,0))-t; //这样求下标 ans=(*lower_bound(t+1,t+n+1,node(x,0))).a; //这样求值 printf("%d %d\n",xiabiao,ans); return 0; } 输入: 5 20 40 30 10 50 35 输出: 4 40
另:upper_bound 的使用与 lower_bound 的使用相似,只不过是严格大于(>)。
int head[maxn], dis[maxn]; bool vis[maxn]; struct node { ll nxt, to, w; }t[maxn]; void add (const int u,const int v,const int w) { t[++tot].to = v; t[tot].w = w; t[tot].nxt = head[u]; head[u] = tot; }
求单源 \(s\) 到任意一点的最短路径。最短路径保存在数组 dis
中。
#include <queue> priority_queue <pair <ll, ll> > q; void dijkstra(int s) { memset (dis, 0x3f3f3f3f, sizeof (dis)); //初始边无限大 memset (vis, 0, sizeof (vis)); //结点初始均为访问 dis[s] = 0; //起点到本身距离为0 q.push (make_pair (0, s)); //起点进队 while (q.size() != 0) { x = q.top().second; q.pop(); //初始结点入队 if (vis[x]) continue; //若是走过,直接跳过 vis[x] = 1; //标记已访问 for (ll i = head[x]; i!=-1; i = t[i].nxt) { ll y = t[i].to, z = t[i].w; if (dis[y] > dis[x] + z) { dis[y] = dis[x] + z; //更新起点到y最短路 q.push (make_pair (-dis[y], y)); //d[y]相反数入队,转小根堆 } } } } int main() for(int i=1;i<=n;++i) head[i]=-1; //后面省略
SPFA能处理负边权,能够判断负环。也能够求最长路。
#include<queue> queue<int> q; void SPFA(int s) { fill(dis+1,dis+1+n,2147483647);//初始边无限大 memset(vis,0,sizeof vis); dis[s]=0; q.push(s); while(!q.empty()) { int x=q.front(); q.pop(); vis[x]=0; for(int i=head[x];i!=-1;i=t[i].nxt) { int y=t[i].to,z=t[i].w; if(dis[y]>dis[x]+z) { dis[y]=dis[x]+z; if(vis[y]==0) { q.push(y); vis[y]=1; } } } } }
可依据最短路代码进行修改。
1. `dis` 数组赋初值时,若是没有负边权就赋 $-1$ ,若是有负边权就赋无限小。
dis[y]>dis[x]+z
中的 >
改为 <
。可在最短路代码基础上进行修改。需新加入一个数组 cnt
,专门记录负环。
补充代码:
ll cnt[maxn];//专门记录负环 void SPFA()..... if(dis[y]>dis[x]+z) { dis[y]=dis[x]+z; cnt[y]++; if(cnt[y]>=n+1)//出现超过n次表示就有负环 { ans=1; //ans=1表明有负环。 return; } if(vis[y]==0) { q.push(y); vis[y]=1; } }
inline void floyd() { for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(e[i][j]>e[i][k]+e[k][j]) e[i][j]=e[i][k]+e[k][j]; }
\(n\) 表明元素个数,\(m\) 为操做数。
\(opt=1\) 时,合并集合 \(a,b\) ;\(opt=2\) 时,若是 \(a,b\) 在同一集合,输出 Y
不然输出 N
。
int find(int k) { if(f[k]==k)return k; return f[k]=find(f[k]); } int main() { n=read(); m=read(); for(int i=1;i<=n;++i) f[i]=i; //初始化本身的老大是本身 for(int i=1;i<=m;++i) { int opt,a,b; opt=read(); a=read(); b=read(); if(opt==1) f[find(a)]=find(b); else { if(find(a)==find(b)) printf("Y\n"); else printf("N\n"); } } return 0; }
int ans,cnt,now=1;//Prim void prim() { for(int i=2;i<=n;++i) dis[i]=MAXN; for(int i=head[1];i;i=t[i].nxt) dis[t[i].to] = min(dis[t[i].to],t[i].w); while(++cnt<n) { int minn=MAXN; vis[now]=1; for(int i=1;i<=n;++i) { if(vis[i]) continue; if(minn > dis[i]) { minn=dis[i]; now=i; } } ans+=minn; for(int i=head[now];i;i=t[i].nxt) { int y=t[i].to, z=t[i].w; if(vis[y]) continue; if(dis[y] > z) { dis[y]=z; } } } }
#include<queue> queue<int> q; //priority_queue<int> q(从大到小排序); q.empty(); //判断队列是否为空 q.size(); //返回队列长度 q.push(item); //对于queue,在队尾压入一个新元素 //对于priority_queue,在基于优先级的适当位置插入新元素 q.pop(); //弹出队首元素 //queue only: q.front(); //返回队首元素的值,但不删除该元素 q.back(); //返回队尾元素的值,但不删除该元素 //priority_queue only: q.top(); //返回具备最高优先级的元素值,但不删除该元素
#include<set> stack<int> s; stack< int, vector<int> > stk; //覆盖基础容器类型,使用vector实现stk s.empty(); //判断stack是否为空,为空返回true,不然返回false s.size(); //返回stack中元素的个数 s.pop(); //删除栈顶元素,但不返回其值 s.top(); //返回栈顶元素的值,但不删除此元素 s.push(item); //在栈顶压入新元素item
set<int> s;//multiset<int> s (不去重) set<int>::const_iterator iter; //迭代器 s.insert(); //插入 s.erase(); //删除元素值 s.empty(); //判断set是否为空,为空返回true,不然返回false s.count(); //返回某个值元素的个数 s.clear(); //清除全部元素 s.begin(); //返回指向第一个元素的迭代器 --s.end(); //返回指向最后一个元素的迭代器 *s.begin(); //返回指向第一个元素的值 *--s.end(); //返回指向最后一个元素的值 //区间形式为 [ begin , end ) ,因此 end 要自减 s.size(); //返回集合中元素的个数 *s.lower_bound(k); //返回第一个大于等于k的元素值 *s.upper_bound(k); //返回第一个大于k的元素值 //若是没有符合条件的值,则输出 s.size() /* 遍历 */ for(iter = s.begin() ; iter != s.end() ; ++iter) { cout<<*iter<<" ";//使用迭代器遍历 }
#include<map> map<string,int> m;//string 是 key,int 是 value。 m.size(); //输出元素个数 m.empty(); //若是 map 为空则返回 true m.clear(); //删除全部元素 ...... m["AKIOI"]=10; cout<<m["AKIOI"]; 输出结果:10
#include<unordered_map> 用法:与 map 差异不大。 优势:由于内部实现了哈希表,所以其查找速度很是的快 缺点:哈希表的创建比较耗费时间 适用处:对于查找问题,unordered_map会更加高效一些,所以遇到查找问题,常会考虑一下用 unordered_map
EdisonBa
2020.11.6 初次编辑
2020.12.1 重大修改