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 重大修改