一些實用的奇技淫巧

今天突發奇想來整理一些小的方法,通常都用來優化程序的(持續更新,想起啥就寫啥)ide

 

 

快速冪大數據

 1 int pow(int x,int y)  2 {  3      int ans=1;  4      while(y){  5           if(y&1)ans*=x;  6           x*=x;y>>=1;  7  }  8      return ans;  9 } 10 
11 快速冪
View Code

適用範圍:這個通常求x的y次方均可以用這個東東,畢竟比正常的運算快的多,固然若是是較小數據能夠直接用位運算優化

 

快速乘法spa

 

1 ll sum(ll x,ll y){ 2     ll cnt=0; 3     while(y){ 4         if(y&1){ 5             cnt=cnt+x; 6         }y>>=1;x=x+x; 7     }return cnt; 8 }
View Code

 

這東西通常都是用於當x*y要對m取餘,可是單純的乘法會直接溢出3d

 

long double黑科技乘法code

1 ll sum(ll x,ll y){ 2     long double cnt=(long double)x*y; 3     long double d=(long double)cnt/m; ll zz=d+1e-6; 4     ll r=x*y-zz*m; r%=m; r+=m; r%=m; 5     return r; 6 }
View Code

這個的運用的位置和上一個相似,x*y對m取餘會溢出的時候,雖然我不懂這東西的原理,只知道這是黑科技,效率高。blog

 

 

讀入優化ip

 

1 int read(){ 2     int x=0,f;char ch=getchar(); 3     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 4     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 5     return x*f; 6 } 7 
8 讀入優化
View Code

 

適用範圍:這個通常都是讀入整數時使用的,讀入快的多,大數據推薦使用,小數據就無所謂了get

 

 

維護前綴和來剪枝(有人說這是利用了A*的思想,我不知道這到底該叫啥,不過看了就知道了)博客

1 int sum[maxn];//前綴和
2 void dfs(int now,int pos){ 3     if(now+sum[n]-sum[pos]<=ans)return; 4     //當前的值加上後來可能會加上的全部值都小於目前的最優答案就跳出 
5  …………………………………… 6 } 
維護前綴和

適用範圍:好比在n個數選m個使總值最大的狀況(有附加條件),用DFS的時候,若是當前的值+以後的全部值(假設後面的都選上)<=當前找出的最優值,就能夠剪枝了

例題:vijos1048

 

 

並查集找環

 1 int find(int x){  2     if(fa[x]==x)return x;  3     return find(fa[x]);  4 }  5 
 6 for(int i=1;i<=n;i++){  7     int u=e[i].u,v=e[i].v;  8     int fu=find(u),fv=find(v);  9     //fa[u]=fu;fa[v]=fv;這句話根據題意判斷是否加 
10     if(fu!=fv){ 11         fa[fu]=fv; 12  } 13 }
並查集

其實這個是並查集的經典用法,或者說這就是並查集的基本操做,說他能找環是由於當fu==fv說明若是在當前的圖上加上這條邊就會出現一個環,這能夠畫圖去感覺

 

 

線形篩

1 for(int i=2;i<=n;i++){ 2         if(!vis[i])prime[++tot]=i; 3            for(int j=1;j<=tot&&i*prime[j]<=n;j++){ 4             vis[i*prime[j]]=1; 5             if(i%prime[j]==0)break; 6  } 7 } 
View Code

 

這個比較經常使用於預處理一些帶素數的題,若是在過程當中判斷一個數是否是素數和容易爆時間,因此預處理後只須要判斷咱們找出的素數包不包含咱們正在詢問的數

至於裏面的break那句實際上是爲了優化這個預處理,由於是i*素數,因此就在素數的倍數的地方停下,由於循環到後面的時候還會對停下的地方後面進行操做,不須要在這裏多浪費時間,這個能夠本身畫圖模擬,仍是很好想通的

 

 

歐拉篩

 

1 for(int i=2,j;i<=N;i++){
2     if(!vis[i])prime[++tot]=i;
3         for(j=i*i;j<=N;j+=i){
4             vis[j]=1; 
5      }
6 }
View Code

 

這個東東可能看起來比較玄學,但其實這個操做是講n範圍內,i的倍數所有標記成了合數,而後j一開始是i*i是由於在以前i-1到2的這些循環中,已經把當前i的2到i-1倍標記過了

這東西適用範圍和線型篩差很少,可是我的更喜歡用歐拉篩

 

 

楊輝三角

1 val[1][1]=1; 2 for(int i=2;i<=maxn;i++) 3 for(int j=1;j<=i;j++){ 4     val[i][j]=val[i-1][j]+val[i-1][j-1]; 5 }
楊輝三角

這個東西通常比較適用於規律題,一個很典型的例子就是noip2016D2T1,赤裸裸的楊輝三角啊,不過那道題是從0,0開始的,那道題裏的i,j位就是在i個數選j個數的方案數

因此考場上打個暴力畫個表格真的頗有必要

 

 

擴展歐幾里得

 

 1 void ex_gcd(int a,int b){  2      if(b==0){  3            x=1;y=0;return ;  4  }  5      ex_gcd(b,a%b);  6      x1=x;  7      x=y;  8      y=x1-(a/b)*y;  9      return ; 10 }
擴展歐幾里得

 

這個式子有點迷,當有ax ≡ 1 (mod b),ax+by=1,擴展歐幾里得求出來的x,y就是這個式子裏面的x,y,至於這個代碼中x,y,x1的轉換是能夠根據換算來證實的,個人另外一篇寫擴歐的博客裏有這個的簡單證實,擴歐的例題:poj1061     vijos1781

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息