【算法】html
【算法】網絡流linux
【算法】樹
ios
【算法】數學git
————【專題】生成樹計數(矩陣樹定理)程序員
————【專題】計數問題(排列組合,容斥原理,卡特蘭數)算法
————【算法專題】卡特蘭數(計數數列)編程
————【專題】數論ubuntu
————【專題】機率和指望vim
【算法】動態規劃windows
————【算法專題】後綴自動機SAM
一個總結性博客:Arya__
【開始模板】
標準模板
#include<cstdio> #include<cstring> #include<cctype> #include<cmath> #include<queue> #include<stack> #include<set> #include<vector> #include<algorithm> #define ll long long #define lowbit(x) x&-x using namespace std; int read(){ char c;int s=0,t=1; while(!isdigit(c=getchar()))if(c=='-')t=-1; do{s=s*10+c-'0';}while(isdigit(c=getchar())); return s*t; } int min(int a,int b){return a<b?a:b;} int max(int a,int b){return a<b?b:a;} int ab(int x){return x>0?x:-x;} //int MO(int x){return x>=MOD?x-MOD:x;} //void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;} /*------------------------------------------------------------*/ const int inf=0x3f3f3f3f; int n; int main(){ return 0; }
fread(空間)
#include<cstdio> char buf[10000010],*ptr=buf-1; int read()//48~57 { char c=*++ptr;int s=0,t=1; while(c<48||c>57){if(c=='-')t=-1;c=*++ptr;} while(c>=48&&c<=57){s=s*10+c-'0';c=*++ptr;} return s*t; } int main() { fread(buf,1,sizeof(buf),stdin); return 0; }
fread(緩存)
const int M=1e5; char ib[M+7],*ip=ib+M; int G(){ if(ip==ib+M)fread(ip=ib,1,M,stdin)[ib]=0; return *ip++; } int read(){ int x=0,f=1; if(ip<ib+M-100){ while(*ip<48)*ip++=='-'?f=-1:0; while(*ip>47)x=x*10+*ip++-48; }else{ int c=G(); while(c<48)c=='-'?f=-1:0,c=G(); while(c>47)x=x*10+c-48,c=G(); } return x*f; }
【隨機/對拍/Linux】
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int seed=123456789;//?? int rnd() {return seed=(seed*1844677ll+1234577)%1000000007;}//%10^9+7 int a[1000010]; void build(int n){ for(int i=1;i<=n;i++)a[i]=i; for(int i=1;i<=n;i++){ int x=rnd()%(n-i+1)+i; swap(a[i],a[x]); } } int main() { for(int T=0;;T++) { FILE*f=fopen("in.txt","w"); /*----------????----------*/ int n=rnd()%100+1; fprintf(f,"%d\n",n); /*----------------------------*/ fclose(f);//Important printf("---%d---\n",T); system("cyc1.exe<in.txt>o1");//bat?? system("cyc2.exe<in.txt>o2"); system("fc o1 o2||pause");//linnux?fc??diff pause??./pause ??pause.cpp???{getchar();return 0;}? } //windows????:tasklist taskkill -f -im sth.exe //linux????:killall GUIDE ps -ef return 0; }
Linux經常使用指令:
編譯:g++ cyc.cpp -o cyc -O2 -Wall(將cyc.cpp編譯後生成可執行文件cyc)
運行:./cyc
顯示路徑:pwd
進入文件夾:cd CYC(返回上一層:cd ..)
殺進程:killall GUIDE
進程列表:ps -ef
Linux對拍:(另寫並編譯文件pause,內容爲{getchar();return 0;})
#include<cstdio> #include<algorithm> using namespace std; int seed; int rnd(){return seed=(seed*1844677ll+1234577)%1000000007;} int main(){ for(int T=0;;T++){ FILE*f=fopen("in.txt","w"); int n=rnd()-500000000; fprintf(f,"%d",n); fclose(f); printf("-------%d--------\n",T); system("./cyc<in.txt>o1"); system("./cyc2<in.txt>o2"); system("diff o1 o2||./pause"); } return 0; }
【RMQ】
void RMQ_init() { for(int i=1;i<=n;i++)d[i][0]=a[i]; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]); } int RMQ(int L,int R) { int k=0; while((1<<(k+1))<=R-L+1)k++; return min(d[L][k],d[R-(1<<k)+1][k]); }
【離散化】
scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&e[i]),w[++lw]=e[i]; sort(w+1,w+lw+1),lw=unique(w+1,w+lw+1)-w-1; for(i=1;i<=n;i++) e[i]=lower_bound(w+1,w+lw+1,e[i])-w;
【STL】
【STL-set/multiset】
set是集合,multiset纔是可重複集合。
set左閉右開,s.begin()返回第一位地址,s.end()返回最後一位以後一位的地址(存儲的鍵值不肯定)
直接調用set獲得地址,須要[*it](int)或[it->x](struct)轉換爲鍵值。
set<int>::iterator it; 定義一個能夠存儲地址的迭代器,迭代即只能it++或it--。
s.lower_bound()
s.upper_bound()
s.find()
s.erase(k)刪除鍵值爲k的元素(也可刪除地址),注意在multiset中必須s.erase(s.find(k))才能只刪除一個元素。
【STL-優先隊列】
(priority_queue)
代碼爲int重載,結構體重載見下面。
#include<cstdio> #include<algorithm> #include<queue> using namespace std; priority_queue<int>big;//大頂堆 priority_queue<int,vector<int>,greater<int> >small;//小頂堆 struct cmp//重載爲從大到小 { bool operator() (const int a,const int b) const {return a<b;}//返回真說明要交換,這與sort中返回真說明不交換是相反的 };//要有分號! priority_queue<int,vector<int>,cmp>q; int main() { int n,u; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&u); q.push(u); } printf("size=%d\n",q.size()); while(!q.empty()) { printf("%d ",q.top()); q.pop(); } printf("\n"); return 0; }
【STL-vector】動態數組
vector之間能夠直接賦值或者做爲函數的返回值。
s.push_back(x)
s.pop_back(x)
s[x]
沒開O2下速度很慢,慎用!
#include<vector> vector<int>p[maxn]; p[0].clear(); p[0].push_back(x);//從0開始! p[0].pop_back(x); if(!p[0].empty);
【STL-bitset】
用於資瓷長二進制。
bitset<100>s;定義s爲100位二進制數。
count計算1的數量。
s=p直接將整數p的二進制賦值給s。
bitset<500>a(0),b(0);//括號賦初值 int number=s.count();//計算1的數量 int number=s.size();//大小 s=0;//總體賦值 s[0]=0; a=b&c;a=b^c;
【STL-permutation】全排列
全排列:指n個數字任意排列,出現的不一樣數列。
下一個全排列:將全部全排列按照字典序排序後,下一個全排列。
只須要定義比較函數就能夠實現全排列,不關注數組內的數字是否相同等。
next_permutation(begin,end),有下一個則返回1並改變數組,不然返回0。
prev_permutaion()同理,上一個排列。
#include<cstdio> #include<algorithm> using namespace std; const int maxn=10; int a[maxn],n; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); do{ for(int j=1;j<=n;j++)printf("%d ",a[j]);puts(""); }while(next_permutation(a+1,a+n+1)); return 0; }
【STL-map】
映射,經常使用於數組太大開不下,或創建string到int的映射。
map<int,int>s;(第一個至關於下標)
s.count(x)判斷下標x是否存在
s[x]=y;賦值
s.erase(x)刪除下標x
s.lower_bound(x)
兩個元素是first和second
#include<cstdio> #include<algorithm> #include<cstring> #include<map> using namespace std; int n,a[100]; map<int,int>s; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); s.insert(pair<int,int>{i+1,a[i]}); } s.erase(3); for(int i=2;i<=n+1;i++)printf("%d\n",s[i]); return 0; }
【STL-string】
長度:size()
輸入輸出:cin>>,cout<<
比較:字典序(常放進map)
拼接:s=s+'x'
【系統時間】
clock()返回long long(不必定表示毫秒),CLOCKS_PER_SEC值爲long long,因此要記得*1.0轉double。
1.0*clock()/CLOCKS_PER_SEC單位轉爲s,類型double,注意*1.0
int t0=clock(); //work... int t1=clock(); printf("%d\n",t1-t0); double t2=1.0*clock()/CLOCKS_PER_SEC; //work... double t3=1.0*clock()/CLOCKS_PER_SEC; printf("%.1lf\n",t3-t2);
【重載】
在結構體中重載運算符。
重載「<」時,priority_queue剛好相反。
好像重載非比較運算符時後面不加const。
struct cyc{ int num,ord; // cyc(){num=0;}//默認初始化 加上後不能直接賦值 bool operator < (const cyc &x) const {return num<x.num;}//重載運算符 }a[100]; a[++n]=(cyc){0,0};//直接賦值
【二分】
二分答案:構造問題-->斷定問題
★遵循左優先原則,即和左比較。
while(l<r) { int mid=(l+r)>>1; if()l=mid+1;else r=mid; //靠左就是最左,靠右就是最右+1 }
是否有等號只是決定要找哪一個數字區間。
l=mid+1 r=mid
★會尋找到對應數字區間的偏大區間第一個數字。
這也只是一個在區間臨界點的與左比較後做出的決策區別而已。
這種方式有邊界問題:即若是序列最後一個數字知足要求,但實際上l-1就沒法對應答案。
★解決辦法是初始r+1,根據左優先原則這個r+1不可能被訪問,但能夠解決邊界問題。
【三分】
初始左右端點l,r
while
左右端點距離≤5時換成暴力。
x1=l+(r-l)/3,x2=l+(r-l)/3*2;
y1=calc(x1),y2=calc(x2);
★更新更劣一側端點。(優勢可能和劣點同側,劣點只有一種可能性)
end.
複雜度O(log3n)。
注意,三分依賴於兩個三分點的大小比較肯定最優解方位,故
若是函數存在平段就不能三分。(除非平段在答案處)
固然也有解決方法,若是整個區間平段就是答案,不然每次任取兩個點,若是平段就再取直到不平段爲止。或者多換一下初始三分點等。
【二進制原理】
1...k中的數能夠由1.2.4...2t.k-2t+1+1(2t+2 > k ≥ 2t+1)組成。
(若1...5,則1.2就能夠組成1..3,而後再加個2就能夠由2+2,3+2獲得4.5。)
原理就是1~$2^t$就能夠構成1~$2^{t+1}-1$了,補個差值$k-2^{t+1}+1$就好了。
實現:枚舉基數指數k,要分解數字爲num,不斷num-=k,直到num剩餘的部分再也不足以支撐一個基數2k時,把剩餘的num加進去便可。
從二進制表示理解,因爲111+111=1110,因此這種作法的實質是:找到最大的111<=x,再加上附加數x-111。
【哈希】
哈希的主要目的通常都是判重,例如疊加給一樣的數字一個附加值,給一樣的字符串附加信息。對於一個數字和一個數組,判斷相同要所有掃一遍數組,時間上承受不起,或者建成一對一斷定的數組,空間上又承受不起,因此找到折中方案:哈希,把數組取模而後作成一些鏈。
哈希空間換時間(和鄰接表同樣把真實狀況堆進一個數組,用頭表記錄位置):MOD通常開到點數三倍大小。
<1>first[MOD](頭表) <2>tot(總數) <3>e[STATE].from(上一個)state(真實值)num(附帶信息)
這三者也是構成鄰接表的核心,對於鄰接表MOD換成點數,STATE換成邊數,再改一下記錄的信息而已。鄰接表是一個點的鄰邊組成一條鏈,哈希表是一個哈希值對應的真實值組成一條鏈。
操做包括:1.取指定數字的附加值:取模後去對應鏈找匹配真實值的數字;2.存入指定數字的附加值:取模後去對應鏈找匹配真實值的數字;3.遍歷:直接遍歷雜亂的原值數組,這時哈希只是在插入時起了判重做用;4.清空:清空頭表first和tot,只有這個操做跟複雜度與MOD大小有關。不過有一種方法:記錄時間戳,每次檢測到舊時間戳就更新之。
struct HASHMAP{ int first[MOD],tot,from[STATE],state[STATE],f[STATE]; void init()//清空 { tot=0; memset(first,0,sizeof(first)); } void push(int number,int num)//插入 { int x=number%MOD; for(int i=first[x];i;i=from[i]) if(number==state[i]) { f[i]=min(f[i],num); return;//已有,不用加入,直接return } tot++; state[tot]=number; f[tot]=num; from[tot]=first[x]; first[x]=tot; } };
字符串哈希見【算法】字符串。
雙hash,其中一個用天然溢出,好像還不錯。
【高級搜索方法】
啓發式搜索(A*算法)
只考慮起點出發的dijkstra算法,每次將點集中距離起點最短的點加入考慮,到達終點爲止。
只考慮終點啓發的BFS算法,每次將距離終點估價最短的點加入考慮,到達終點爲止。
啓發式函數f(n)=h(n)+g(n),g(n)表示從初始結點到任意結點n的代價,h(n)表示從結點n到目標點的啓發式評估代價
啓發式函數能夠控制A*的行爲:
1.若是h(n)是0,則只有g(n)起做用,此時A*演變成Dijkstra算法,這保證能找到最短路徑。
2.若是h(n)常常都比從n移動到目標的實際代價小(或者相等),則A*保證能找到一條最短路徑。h(n)越小,A*擴展的結點越多,運行就得越慢。
解釋:h(n)較小時,終點的啓發性較差,結點就會四處拓展,速度較慢。h(n)比實際小就不可能影響最短路徑的決策。
3.若是h(n)精確地等於從n移動到目標的代價,則A*將會僅僅尋找最佳路徑而不擴展別的任何結點。這就是A*求解第k短路的原理。
4.若是h(n)有時比從n移動到目標的實際代價高,則A*不能保證找到一條最短路徑,但它運行得更快。
解釋:h(n)較大時,終點啓發性很強,結點會趨向終點方向拓展。
5.若是h(n)比g(n)大不少,則只有h(n)起做用,A*演變成BFS算法。
A*的核心是估價函數的設計——結合啓發式函數和常規函數。
迭代加深搜索(ID算法)
從小到大枚舉深度上限maxd,每次執行只考慮深度不超過maxd的結點,至關於強行規定解的深度避免無限度搜索。
只要解的深度有限,就必定能在有限時間枚舉到。
IDA*算法(ID+A*)
在迭代加深搜索的基礎上,設當前深度爲g(n),樂觀估價函數爲h(n),若是g(n)+h(n)>maxd時應該剪枝,這就是IDA*算法。
【其它算法】
【分數規劃】轉換爲與0的斷定問題
【搜索】
剪枝:可行性剪枝,最優性剪枝
可行性剪枝:奇偶性剪枝、剩餘和不可達剪枝
【倍增】每次變化規則必須相同並知足結合律!
【折半搜索】Meet-in-the-middle思想的一些應用
尋找a+b+c+d=0,轉化爲a+b=-(c+d),一邊哈希一邊枚舉。
對於n的選擇,分紅兩個值數組,分別存儲先後n/2的數字組合出來的數字,而後兩個指針(從大到小和從小到大)順序考慮合併。
【暴力DFS】
dfs括號內存對應參數。
哈希:排序後作成base進制數判重。
【進制轉換】
十進制轉二進制 while n>0 do begin inc(num); a[num]=n mod 2; n:=n div 2; end; 二進制轉十進制 now=1 for i=1 to num do begin ans:=ans+a[i]*now; now:=now*2; end;
【後綴表達式】
【高精度乘法(high*low)】
x=0; for(int i=1;i<=lens;i++) { x+=sum[i]*num; sum[i]=x%10; x/=10; } while(x>0)sum[++lens]=x%10,x/=10;
【高精度除法(high/low)】
【字符串哈希】
const int MOD=100000007; int Hash(char ch[]) { int s=0; for(int i=0;i<strlen(ch);i++) {s*=27;s+=(ch[i]-'a'+1);s%=MOD;} return s; }
【貪心】【BZOJ】1828: [Usaco2010 Mar]balloc 農場分配(經典貪心)
【指針】
int *a; 定義指向int的指針a
*a 取地址的變量
a-->b 取地址的結構體變量
&a 取變量的地址
【基數排序】
對於每一段:
①memset
②桶加A
③指針數組指向新數組B
④賦值給指針數組A
⑤swap
namespace Qsort{ int *s[300],a[maxn],b[maxn],T[300]; void qsort(int *a,int n){ int *A=a,*B=b,*mp; int mx=256; for(int k=0;k<4;k++){ memset(T,0,sizeof(T));mp=B; for(int i=0;i<n;i++)T[A[i]>>(8*k)&255]++; for(int i=0;i<mx;i++)s[i]=mp,mp+=T[i]; for(int i=0;i<n;i++)*s[A[i]>>(8*k)&255]++=A[i]; swap(A,B); } } }
【RMQ-LCA】例題: 樹上的最遠點對
dfs序:每一個點的入棧出棧序,能夠選擇記錄出棧點或不記錄。(方便查詢子樹,若是記錄入棧+1出棧-1則能夠維護點到根的路徑:星系探索)
歐拉序:中序遍歷,每次遍歷到就記一次。
歐拉序求LCA:兩點區間的深度最小值,用RMQ求解。
歐拉序求子樹權值和:查詢該點在歐拉序中最後出現的位置的前綴減去第一次出現的位置-1的前綴和。
【哈夫曼樹】Huffman Tree
哈夫曼樹又稱最優構造樹,是使樹的帶點權路徑長度和最小的樹的形態。
帶點權路徑(WPL)=點權*深度。
構造方法:每次取點權最小的兩個根節點做爲左右子樹(左小右大)組成新根節(點權爲左右之和),屢次操做直到只剩一棵樹。(相似合併果子)
哈夫曼編碼:從根出發左0右1,走到每一個字符的二進制就是它的編碼。
Huffman Code是電文總長最短的二進制編碼方式,將n個字符的出現頻率做爲點權構造哈夫曼樹獲得的就是對應的哈夫曼編碼。
例題:【CodeForces】700 D. Huffman Coding on Segment 哈夫曼樹+莫隊+分塊
【暫存】
http://www.cnblogs.com/ka200812/archive/2011/09/02/2164404.html
消(tui)遣(fei):http://mp.sohu.com/profile?xpt=c29odWJsb2diaXpAc29odS5jb20=
http://blog.csdn.net/qiankun1993/article/details/6765688
http://blog.csdn.net/kk303/article/details/6692506
【競賽核心原則】
1.調試:常見難調錯誤有,[變量類型long long和1ll],[語句順序顛倒],[初始化]。
細心考慮全部可能的特殊狀況,一失足成千古恨。
過了樣例,爲了保證正確能夠手動模擬一下中間過程。
善用靜態差錯,冷靜地逐行分析能夠省掉一大堆無謂的調試時間。
不要盯着代碼一直看,靜態查不出錯就必須勤動手,別懶。
勇於重構代碼的勇氣,有舍纔有得,重構的過程也能查出錯誤。
調試的時候打開O2,能夠查錯(特別是數組越界)。
2.思考:題目都是簡單的,一旦對題目產生畏懼就再也想不出來了,不用懼怕最後一題。
看清題意,思路清晰,一步一步轉化,不要一團亂麻。
把想到的東西寫下來,把可能的公式列出來,可能就會有新的發現。
多寫寫公式,多進行數學推導。DP多試幾種表示。
不要考慮太多奇怪的細節,把握好大局。
別怕常數,別畏畏縮縮,相信本身!1s能夠跑4億純循環!
想不出來的題目就換個角度想,換個思路。
再想不出來的題目就換個算法,腦洞開大。
二分答案不少時候是打破僵局的重要思路。
3.策略:先寫暴力,即穩定得分,又方便對拍。善於對拍,沒對拍的題能AC是運氣。
切忌戀戰,不要猶豫,想不出來趕忙跳,否則追悔莫及。
不會寫正解時,僞裝看錯題意,簡化算法來騙分。
think twice,code once,動手前必定要把正確性思考清楚。
NOIP和NOI都是部分分比賽,不要太貪心卻是該拿的分沒拿穩。
(暴力拿滿就能省一,暴力寫好就能進隊,暴力寫全就能碾壓。)
(題目是難的,數據是水的,出題人是懶的。你永遠不知道你的暴力能搞多少分。)
4.心態:心態平穩,到最後一刻也不要放棄,相信本身。
★珍惜時間!合理分配比賽時間,切忌前鬆後緊!
考試結束前5分鐘改代碼大機率是錯的,改代碼前必定要冷靜!
5.命名空間,部分分利器。
namespace Task1{
void solve(){}
}
int main(){
if(check1()){
Task1::solve();
return 0;
}
}
6.補充
自信,相信本身寫的沒錯,好好調。
一直看不出錯,說明錯在通常不考慮的位置。
不要猶猶豫豫,先寫好寫的暴力。
能拿的分不丟,不會的分儘可能騙 1.會作的subtask不丟分:若是一個subtask你會作,好比遇到了水題,或者某道題你會寫30分的小數據,那麼請務必確保你能拿到這部分分數。以及,不要嫌分數少而懶得寫!30分也是分,10分也是分,在分數拉不開的狀況下(若是你水平並不優秀,這就是你老是要面對的狀況),10分的差距就決定了你是一等仍是二等。 請你們記住:在大多數OI比賽中,只要暴力分所有拿到,就是一等獎。 2.常見有效騙分算法試舉例:數據是死的,人是活的,出題人是懶的 * 若干個錯誤的貪心、動態規劃取最優解,一個數據同時卡掉多個錯誤算法很難 * 暴力算法加奇怪剪枝,出題人不必定想獲得你的奇怪剪枝,所以不必定卡的掉 * 基於某些東西的暴力(好比樹上的題目和深度有關、和點的度數有關的暴力等) * 代碼的常數優化,配合上述優化,進一步增長卡過去的可能性 3.本着「先拿確保能拿到的分數」的原則,建議先把會寫的分數都寫出來。不會的題目的暴力也都應當寫一下,由於若是你最後沒作出來,那暴力能夠交上去拿樸素分;若是你最後作出來了,也須要暴力來對拍。同時暴力也能爲正解提供一些思路。 4.方法/技巧: * 使用草稿紙,有用的性質均可以記錄下來,零散的思路也能夠畫下來,這頗有助於思考。 * 嘗試增強/放寬題目的條件/約束,獲得更特殊的模型。思考特殊模型的解法並嘗試推廣到原問題。 * 探索是否存在隱藏的性質,嘗試從邊界、特殊狀況開始考慮,猜想、證實性質。 * 是否能換一個思路?從反面思考是否更簡單?是否能夠利用二分答案之類的技巧進行轉化?NOIP的題目對思惟深度的要求通常不高,若是想了好久都沒想法,多是你思惟方向錯了。 * 某某算法是否可能應用於這個問題?逐一肯定。(若是你有思惟死角,好比老是想不到用某個算法,能夠考慮這樣) 5.多去上廁所,不要讓本身長時間陷入某項工做(思考、調試)中。 緣由一是人在長時間思考或調試時會效率降低,並且容易鑽牛角尖,陷入錯誤的思路中。 二是時間也會不知不覺中過的特別快,容易出現相似「臥槽考試只剩一個半小時了還一點想法沒有怎麼辦」這種很糟糕的狀況。 所以,若是你想了一段時間卻毫無想法/調試了好久找不到問題所在,請務必從中跳出來,換一個思路,切勿陷入其中,白白浪費時間。 6.會作的題不要寫錯! 不會作的題,要寫暴力!要騙分! 不要鑽牛角尖,高效利用時間! 不管發生什麼,保持心態穩定! 7.低級錯誤: * 文件名打錯/忘記用文件輸入/忘記用文件輸出/忘記關文件 * 數組開小 * 爆了內存限制 * 運算時爆int,忘記強制轉換爲long long * 對答案取模的題目有地方忘記取模 * 輸出時格式錯誤 * 輸出64位整數時沒有用%lld * 提交時交錯文件/打錯擴展名 8.知識性內容 * 模擬、枚舉、爆搜、高精度計算等較基礎內容 * 貪心、構造、結論題等比較坑的 * 動態規劃及其優化(之前出過單調隊列,但會不會出現更難的就不知道了) * 基礎數據結構(部分和、簡單的線段樹等常見的維護方法) * 樹論,樹形dp,樹上的數據結構(lca,倍增祖先,dfs序等) * 圖論,最短路,最小生成樹等 * 簡單數論(逆元、快速冪、素數篩法、中國剩餘定理等) * 常見轉化方法(二分答案、分治等)、常見技巧(壓位等)、推理分析的能力 9.經常使用的性質證實方法:調整法,對這種「從新排列」某個序列,要求最優化某個東西的題目,能夠考慮「某個解若是交換相鄰兩個元素,什麼狀況下會變優」或「最優解的元素次序間必須知足什麼樣的性質,才能使得無論怎麼交換都得不到更優的解」,進而發現有用的性質。 放縮法:放寬/增強約束條件。
【技巧】
珍惜時間啊>w<!!!只有4小時QAQ!!!
沒有難題,只有複雜題,不要懼怕複雜的題目,可能都是簡單的算法!!!
不要懼怕第四題!!!
1.超級無敵貪心,部分貪心(小數據暴力,大數據貪心)。
2.隨機化O(n*m*k),調用clock計算出知足時間上限的最大值,記錄下乘積。
3.字符串哈希,哈希判重。哈希↑。
4.隨機化算法:登山、退火。
5.求不出來的量、未知量就枚舉二分三分(其實不少時候是正解)。
6.二分將求值問題轉化爲斷定問題。
7.環:最短路遇負環X最長路遇正環X——圖論tarjan縮點或網絡流消圈
8.奇怪的題能夠暴力打表找規律,不慫!敢寫敢幹!就算找不出規律,
也能夠暴力跑表放進代碼裏(注意長度限制),const int a[1000]={...}。
9.要改寫暴力就別猶豫,該造數據/對拍就造數據/對拍。
10.sort複雜度怕過不去就試試基數排序。
11.心態:遇到複雜的題目描述也不用懼怕,其實都是咱們熟悉的算法,建模出來就沒問題了。
注意看數據範圍大體考慮一下算法。說不定考慮到最後搜索就是正解呢。
12.一些差值問題、區間問題能夠考慮差分。
13.樹考慮樹型DP
14.奇怪的DP若感受有依賴關係,要麼考慮一動一不動,要麼把狀態表示出來。
多維DP,求其中一維最優,令另外多-1維轉移。
不要一開始就胡思亂想一些奇怪的細節,要把大方向定下來,找出不變的因素,狀態表示出來後再想狀態轉移就不難了。
每每狀態表示纔是重點!
不要考慮太多奇怪的細節,大局把握好!
我想題最大的缺陷是老是容易陷入一些浮於表面的奇怪細節,自覺得是該題的特色,大局觀較差。
15.沒事打表找規律
16.先寫好寫的暴力,而後出正解也能夠對拍。
17.時間戳避開頻繁的初始化,多組數據也是如此,dfn。直接memset有超時的風險。
18.搜索均可以嘗試記憶化。
19.依賴關係:揹包||閉合圖||樹型DP||圖論
20.精度大一點(不T),老是好的>_<
首先能夠發現若是平均值是已知的那麼其實全部邊的邊權就能夠直接計算出來了. ( ((((一些數對另外一個數的差)的平方)的和)的最小值)必定在這個數是這些數的平均值時取到) 因此能夠枚舉平均值而後直接計算出當前的最小生成樹即爲一組解. 而後設f(x)爲在mid = x時所獲得的答案. 發現f(x)的函數圖像是一個波形函數,不過週期很長. 因此三分一次獲得正確解的可能性很大. 因此隨機左右端點多三分幾回就好啦QAQ...
21.難以實現的功能真的能夠嘗試直接枚舉!
22.當心看漏條件和讀錯題,反覆看清楚和想清楚再下手,切莫衝動,一旦下手切莫拖延!
23.隨機大法好:限時隨機化 貪心出奇跡 貪心代替DP轉移 預處理而後隨機化O1算出答案求min或max
24.小範圍暴力大範圍高分水法。
25.狀態壓縮每每是提升效率行之有效的辦法,如把30個bool壓成int。
26.對於無環連通塊,點數-鏈接數=1。
27.忽略題目條件,鑽數據漏洞,考慮缺陷算法。
28.調和級數:枚舉公差,1~n中等差數列枚舉,複雜度n log n
29.暴力:雙向搜索,中間相遇,meet in the middle,兩邊搜,中間合併。
30.差分思想,(x,y)=(1,y)-(1,x)
還有一種在L打+1,在R+1打-1,維護前綴和便可知道左閉右開區間信息。
31.預處理,或者記憶化,都是避免算重複提升效率。
32.線段樹出奇跡,有神奇的左右子樹性質,每次詢問修改都會訪問到對應子區間。
只須要記錄答案對應變量,維護好左右合併的狀況,就有不少題都能用線段樹作啦。
33.最大最小數字--->字典序--->保證不升序或不降序!越前越極!無腦前先極致使了不升或不降。
34.離線出奇跡。
while別寫成if。。。
35.二分就是二分答案,當答案具備單調正確性時就能夠二分。
36.靜態差錯好東西呀!
37.無向無環圖就是樹!!!
38.求移動區間最值,使用單調隊列優化。
39.注意設置初值,特別是long long。當有調試輸出的時候,沒有初值的元素就可能被隨意給初值。
40.貪心算法一般能夠加入反悔措施來保證正確性和複雜度,網絡流也是這樣的思路(反向邊)。
41.使用set時經常是multiset!!!別用錯了!!!很難查出錯的!!!
42.套路:模2=取反=異或
43.序列交換問題:總體挪位用樹狀數組維護,總體前移就從1到n依次處理(開鄰接表),剩下的位置不會變化。
44.取模有減法的時候必定要+MOD(即便是大-小,取模也會出現負數),取模有除法的時候必定要求逆元。
45.二分就是二分答案,答案斷定具備單調性。
46.單調隊列:移動區間最值。
47.經典貪心:【BZOJ】1828: [Usaco2010 Mar]balloc 農場分配(經典貪心)
48.揹包方案統計:g[i][j]=0/1表示從上面轉移來(不選)或從左上轉移來(選)。
一維排序後使用揹包CF864 problemE
49.多點距離用總距離減去座標距離和,如【UOJ】#49.鈾倉庫
50.用加法構成數字時,能夠考慮全部數字都由二進制分組構成。
51.樹上路徑統計:在LCA處,每一個點和前面的子節點統計後加入。
52.位運算和二進制必定要考慮拆位。
53.看到16必定要想到狀壓和3^n枚舉子集。
54.異或能夠差分,xor(i~j)=xor(j)-xor(i-1)。
55.樹上路徑差分:x到根+y到根-lca(x,y)到根+fa[lca(x,y)]到根。
因此樹上路徑題目除了樹鏈剖分,還能夠考慮差分離線。
56.給定最短路圖的題目,每每要建徹底圖,而後再考慮刪邊或選邊。
57.可持久化權值線段樹(主席樹)用於快速解決區間權值詢問問題。(區間第k大等)
58.線段樹合併用於解決一堆數組的合併,經過簡化表示同時解決時間和空間不夠的問題。
59.樹上最短和次短問題能夠轉化爲最短和子節點最短再並起來的問題。
60.看到區間操做就要想着化成2個單點操做。
61.隨機數據下的序列,LIS的指望長度爲log n。考慮將序列按順序加入二叉查找樹,LIS就是最右一條鏈,深度指望Log n。
【零碎の東西】知識&&錯誤
★linux下取模能夠爲負。
★記得開最大警報+O2優化
★記得開long long,換%lld。或者乘1ll臨時轉方便取模等。
★long long=1ll*int*int
★記得取模
★long long和struct要初始化!
★過了樣例必定要細心+耐心地檢查代碼
while不要寫成if
★while不要寫成if!經常檢查不出來!
多組數據時,碰到要初始化的變量立刻回去初始化。
多個輸出該換行記得換行
long long(9*10^18)範圍10^18(1後18個0)及如下
unsigned
const int inf=0x3f3f3f3f;
const long long inf=1ll<<60;
循環隊列要while(head!=tail)
lower_bound(a+1,a+n+1,x)-a 找到a數組中第一個≥x的數的位置
upper_bound(a+1,a+n+1,x)-a 找到a數組中第一個≤x的數的位置
tot=unique(a+1,a+tot+1)-a-1;去重並獲得新數組元素個數tot
100000007(>10^8)爲素數,1和7中間夾7個0
985003爲素數
memcpy(載體,來源,個數),起始位置能夠經過在載體和來源處±1(改變指針指向位置)來改變。
個數:int類型*4,ll類型*8,char類型*1
-O2優化(比賽或測評通常都會開)會對未定義行爲任意操做以達到優化的目的
因此會卡掉數組越界、變量未定義初值、子程序無返回值等。
平方操做-->斜率優化?
任意底的log,均可以用log(x)/log(底)湊出來
cmath-log(x)返回e爲底x的對數,exp(x)返回e的x次方。
exp(log(x))==x(±eps)
scanf("%c %c",c1,c2)中間加空格能夠一直跳到下一個有效字符(即空格和‘\n’)
要取模的題減法記得+mod。
位運算最快,因此在二進制操做中能夠用||和^代替+和-。
int有0~31位(1<<x,x=0...31),最高位(31位)是符號位,正數爲0,負數爲1。
long long有0~63位,最高位(63位)是符號位。
1<<32開始不合法,必須寫爲1ll<<32(即long long)。
或:(運算)‘l’ (條件)‘ll’
for i--
#define int long long int==signed(!=unsigned)
[byte]bool-1 int-4 long long-8 1byte==8bit
可輸出sizeof(類型)表示單位大小,sizeof(變量/數組)表示其大小
struct通常會將其全部元素對齊至佔位最大元素的大小,具體要用sizeof測定
比賽時數組不能開到太臨界(128->110),堆棧大概10w~100w層,佔幾M空間。
double佔8字節(long long),long double佔16字節(聽說較慢)。
浮點數都是從最高位開始算有效數字位的,有效數字:double爲15~16位,long double爲18~19位。
中間不要取模否則相減會出錯。
scanf返回讀入數據項數(字符數組也算1),未成功讀入返回0,失敗或文件結束EOF返回-1(EOF=-1)。
‘~’表示含符號位的按位取反操做,實際效果是0和-1,1和-2,2和-3,正數與其相反數-1配對。
'^1'和1異或能夠將對應二進制位取反,和0異或則不動。
1ll* 取模臨時轉long long
unsigned long long 輸出佔位符:%llu 強轉:1ull*
通常出現奇怪的數字狀況極可能就是數組越界。
在樹上使用鄰接表必定要記得判斷父親。
優先隊列刪除:優化dijkstra那種作法
if(~a)...~(-1)=0
二進制枚舉子集的子集(不包括空集):for(int i=st;i;i=(i-1)&st) 每次減1而後&掉多餘的不在其位的1。
枚舉總集全部集合再枚舉子集,複雜度O(3^n),每一個點只有三種可能(子集+子集,非+非,子+非)
使用long long時要1ll<<x!!!
線段樹要開4倍空間!
RE:除0,訪問界外,數組開小。
開long long記得快讀改返回值爲ll。
多關鍵字double快排的cmp要這麼寫return fabs(a.x-b.x)>eps?a.x<b.x:a.y<b.y;
eps不要調過小,調到合適的值,給本身的精度偏差一點空間。1e-10炸了,1e-6過了看狀況從1e-3~1e-13調(不排除1e-1)
複雜度爲n log n時,離散化儘可能寫O(n)的,O(n log n)只在須要額外的二分查詢時才寫。
STL使用時後面都帶括號。
set<int>::iterator it;
時刻檢查數組大小,特別是要開雙倍數組的時候。
STL容器左閉右開,失敗就跑到end處。
末尾0的個數看2*5的數量,小學奧數233
int轉double時要注意1.0*的地方要全面。
邊表用tot,其餘地方不要重!!!
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa)
實數類型沒有等於!!!
奇怪問題都是空間開小!
無向圖不要e[i].v!=fa。
快速取模:ans=(ans+1ll*x*y)%MOD等價於ans=mod(ans+mod(1ll*x*y)),mod中對MOD^2取模,最後再取模MOD。
求解二次方程的時候要注意判斷A=0的退化一次狀況,不然除0。
2的逆元是(MOD+1)/2。
邊maxm無腦開兩倍。
須要頻繁memset的時候記得把數組空間開小,時間戳和垃圾回收都能取代memset以加速。
分清楚[&]和[|]。
樹鏈剖分記得調用兩個dfs!!!寫了dfs2要記得調用!!!
樹鏈剖分find時比較的是頂點深度!!!
注意常見錯誤——變量操做順序,先運算最後賦值。
結構體總體賦值的時候,注意變量設置順序問題。
操做順序!語句操做順序!先dfs後操做!\
變量名不要起大小寫,不要起容易混淆的變量名。
3個inf相加會爆inf!
枚舉變量名ijk尤爲注意。
as是iostream的關鍵字,pow是cmath的關鍵字。
注意經常使用名字,多個地方不要使用同一vis等。
給的位置不必定有序,記得排序。
樹上差分必定要u+1,v+1,lca(u,v)-2,不能再lca處加。
Dijkstra若是TLE確定是堆開反了。
初始化0 1 2和1 2 3的區別。
2的逆元:inv(2,MOD)=(MOD+1)/2。
make 0 no influence:數據結構中爲了方便經常用0表示空節點,這時候全部修改操做都要注意不能修改到0的值,使其對全局不影響。
輸入取摸!!!
局部變量和全局變量的致命問題。(WC)
調代碼多動手輸出。
基排數組的值域不能用n,用mx。
【其它】
【卡常】
1.取模若是是加法用子程序MOD比直接取模快三倍。
2.4億的純循環恰好1s。
3.剪枝大法好,但要注意不要剪過頭。
//4.所有函數名前面加inline,有益無害。
★5.手寫max,手寫min,dev C++編譯器的max和min慢到極點。
6.線段樹常數巨大QAQ
查詢最小值能夠query剪枝。
區間操做複雜度O(4*log n)(無關區間大小),單點快於區間。
從頭開始查比從中間開始查更快。
★7.用fread快速讀入!
//8.減小傳參多開全局減少常數。
//9.結構體不要太大,儘可能用數組。
wys課件 底層優化
【初賽】前面題目快速過只寫一眼題,把程序補全和看程序寫結果完成後再回來慢慢推。
1.NP!=P
P問題:能夠多項式時間內求解的問題
NP問題:能夠多項式時間內驗證解的問題
NP-Hard問題:全部NP問題均可以在多項式時間內歸約爲NP-Hard問題。
NPC問題:是NP-Hard問題,也是NP問題。(全部NP問題均可以多項式時間歸約到此問題,同時此問題能夠多項式判解)
也就是解決了一個NPC問題就解決了全部NP問題(即NP=P)
著名的有SAT、TSP(旅行商)、哈密頓迴路、揹包問題等。(全部斷定性問題均可以構形成SAT問題)
關係圖:簡單理解 NP, P, NP-complete和NP-Hard
NP-hard也存在不是npc的部分,這部分即便np=p也不能多項式時間判解或驗證解,如找一個完美的女友。
2.電子管-晶體管-集成電路-大規模集成電路-生物\光\量子計算機
計算機硬件:計算器、控制器、存儲器、輸入設備、輸出設備
①中央處理器(CPU)由運算器、控制器和一些寄存器組成。
②存儲器:內存(主存、緩存)和外存
緩存:速度快,容量小,位於CPU和主存之間。
主存:只讀存儲器(ROM)不因斷電丟失信息、隨機存儲器(RAM)因斷電丟失。
外存:硬盤、軟盤、光盤、U盤
③總線:各部件的公共通道,多條導線。
3.信息計量:1Byte(字節)=8bit(位,比特)。
4.運算中所有轉化爲補碼運算。
原碼:1符號位(0正1負)+7數字位
反碼:正數同,負數反碼符號位1+數字位按位取反。
補碼:正數同,負數爲反碼+1。
5.面向對象的編程語言:C++,C#,Java,Visual Basic
6.Internet服務與協議:
IP地址分配協議:IPv6協議
地址:URL
網絡體系:(物理層-數據鏈路層-網絡層)-運輸層-(會話層-表示層-應用層)
超文本傳輸協議:HTTP
電子郵件協議:SMTP發送,POP3接收
遠程登錄協議:Telnet
文件傳輸協議:FTP
以上都屬於TCP/IP協議簇,屬於應用層協議。
傳輸層:傳輸控制協議TCP
端口是TCP和UDP與應用程序打交道的訪問點。
7.網絡體系
國家頂級域名:cn(中國)、us(美國)、uk(英國)
國際頂級域名:int
通用頂級域名:com、net、edu
網絡體系:OSI體系和TCP/IP體系,傳輸方式是頂到底到底到頂。
8.二進制小數轉十進制:num*2^(-x),小數部分和整數同樣都是乘權。
十進制轉二進制小數:每次乘2後取整數位。(只有2^(-x)的小數才能轉二進制)
【神奇の博客們】
百度:HEOI 2017 遊記&&省選 總結
http://paste.ubuntu.net/ 貼代碼
http://blog.csdn.net/ACdreamers
http://orzwzh.com/
http://www.jkxing.net/post/jiu-ri-oi/2016-09-20
http://blog.csdn.net/zxy_snow/article/category/780782
http://www.xysay.com/
http://lib.csdn.net/base/datastructure 算法與數據結構知識庫(基礎?)
http://www.cnblogs.com/daoluanxiaozi/
很強的blog:http://www.cnblogs.com/pony1993/
http://www.matrix67.com/
OI blog:http://www.cnblogs.com/suishiguang/
http://www.cnblogs.com/iwtwiioi
http://blog.csdn.net/PhilipsWeng/article/category/2473431 (weng wen tao?)
http://blog.csdn.net/PoPoQQQ 超穩
http://www.cnblogs.com/kuangbin/ 總結超好
liu_runda 衡水高二大佬
過去的2015-claris
http://www.cnblogs.com/lidaxin/ 封面換圖dalao
時間並不會由於你的迷茫和遲疑而停留,就在你看這篇文章的同時,不知道有多少人在左思右想,在爲算法廢寢忘食,不知道有多少人在狂熱地拍着代碼,不知道又有多少提交一遍又一遍地刷新着OJ的status頁面……
沒有誰生來就是神牛,而千里之行,始於足下!
https://www.bilibili.com/blackboard/activity-Miku10th.html MIKU!
AC. 夢想 好多友鏈 http://www.acyume.com/archives/456
D_Double's Journey實用技術博客。vim