世界五星级大厨经典菜品集
本blog只是記錄C++學習以來掉過的一些坑,寫下來防止自己下一次再犯,順便分享
持續(xù)更新,到死為止
- 菜品特套1:vector.size() '~' 的使用
- 菜品特套2:if-else的縮進
- 菜品特套3:int范圍邊界的1ll使用
- 菜品特套4:內(nèi)存計算
- 菜品特套5:全局變量和局部變量的重復
- 菜品特套6:順序結構&& ||前后順序
- 菜品特套7:scanf("%s")與換行符的愛恨情仇
- 菜品特套8:break
- 菜品特套9:,;的差距
- 菜品特套10:STL的map/set
- 菜品特套11:C++的執(zhí)行順序
- 菜品特套12:順次處理字符讀入
- 菜品特套13:傳地址的動態(tài)開點
- 菜品特套14:異或判斷相等的偷懶
菜品特套1:vector.size() ‘~’ 的使用
???
for( int i = G[u].size() - 2;i >= 0;i -- )???
for( int i = G[u].size() - 2;~ i;i -- )食用說明書食用說明書食用說明書
~:是用來判斷是否為-1的簡便寫法
常見用法👇
跟前向星套用
memset( head, -1, sizeof( head) ); ... for( int i = head[u];~ i;i = nxt[i] )還有無限輸入的判斷
此時與EOF產(chǎn)生的作用一樣
while( ~ scanf( "%d", &n ) ) //也可寫作 while( scanf( "%d", &n ) != EOF )以上操作一但出現(xiàn)符合=?1=-1=?1就會結束程序,跳出循環(huán)……
但是倒回去仔細看錯誤的寫法,看似正確實則暗流涌動,一句話就可以直擊要害
G[u].size()==0G[u].size()==0G[u].size()==0的時候怎么辦?!! 減完后變成?2-2?2
此時是判斷不出來的,就會一直死循環(huán)?2-2?2下去!
PS:此問題來自哲學的微笑——老劉,瘋狂嘲笑哈哈哈哈
菜品特套2:if-else的縮進
???
if( ... ) {for( int i = 1;i <= n;i ++ )if( ... ) } else {... }???
if( ... )for( int i = 1;i <= n;i ++ )if( ... ) else...食用說明書食用說明書食用說明書
如果if?elseif-elseif?else和forforfor是這么操作,那么運行就會很正常
滿足ififif條件就執(zhí)行iii的循環(huán)
否則執(zhí)行jjj的循環(huán)
但是當我們在循環(huán)里面再次嵌套條件語句的時候,此時就問題大大滴了!!
if?else用法if-else用法if?else用法
我們要了解if?elseif-elseif?else的運行原則,elseelseelse在不加{}\{\}{}強制區(qū)分的時候,是默認否定離它最近的ififif情況
也就是說,在錯誤寫法中,elseelseelse否定的是forforfor循環(huán)里面的ififif條件
if?elseif-elseif?else是算一條語句的,嵌套在循環(huán)里面時,就可以不用打括號
for( int i = 1;i <= n;i ++ )if( ... ) ...else ... //上面寫法等價于下面的寫法 //如果if,else里面有多條語句的時候 //注意要打括號,不然if-else會被中斷,出現(xiàn)CE for( int i = 1;i <= n;i ++ ) {if( ... ) ...else ... }if?elseif-elseif?else是一條語句,所以中間是不能被其它非if?elseif-elseif?else語句打斷
for( int i = 1;i <= n;i ++ )if( ... ) ...n = n + 1;else ... //這個時候會if-else編譯報錯,并且提醒我們?nèi)鄙俅罄ㄌ?/span>往往題目的情況不止簡簡單單的兩種,這個時候我們一樣處理
for( int i = 1;i <= n;i ++ ) if( ... ) ...else if( ... ) ...else if( ... ) ...else ... //兩種寫法是等價的 for( int i = 1;i <= n;i ++ )if( ... )else if( ... ) ...else if( ... ) ...else ...綜上,總結一下:
我們的縮進只是為了代碼可觀,邏輯清晰易懂
但是程序運行有自己嚴格的規(guī)則,并不是智能AI
程序并不會按照我們的縮進,智能分類匹配if?elseif-elseif?else
PS:此問題出自蒟蒻博主,例題“zamjena”,當時調(diào)了好幾天,自己也發(fā)現(xiàn)了加括號和不加括號會有答案的區(qū)別,但是當時沒有意識到本質(zhì)的原因是什么
博主自我反思:
有的時候覺得if-else很簡潔,而且我自己不太喜歡打大括號,從而可以縮減代碼行數(shù)
現(xiàn)在細想來覺得還是應該從嚴謹邏輯的角度出發(fā),還是打個大括號,避免這種分歧
菜品特套3:int范圍邊界的1ll使用
???
long long n = 1ll << 31 - 1; //運行結果:2147483647???
long long n = 1 << 31 - 1;食用說明書食用說明書食用說明書
有符號整型int:232int:2^{32}int:232,占用4字節(jié),32bit
然而取值范圍[?231,231?1][-2^{31},2^{31}-1][?231,231?1]
無符號整數(shù)unsigned_intunsigned\_intunsigned_int取值范圍就可以達到[0,232?1][0,2^{32}-1][0,232?1]
C++計算的時候是默認intintint類型,也就是說如果我們不強調(diào)1ll1ll1ll,111就只申請了intintint類型
我們可能會以為:我左邊儲存答案的變量開了longlonglong\ longlong?long啊,這不存的下嘛
其實不然,可以理解為是右邊每個計算部分存好后再統(tǒng)一進行操作
然后放到左邊變量里面,并不是直接在左邊變量里面操作
延伸拓展👇
請看接下來的兩種操作寫法
int A, B; long long n = A + B; long long A; int B; long long n = A + B;將A,BA,BA,B賦值214748364721474836472147483647
會發(fā)現(xiàn)第一種寫法溢出了,而第二種寫法算出了正確答案
這是因為A+BA+BA+B暫時將結果存在了AAA里面,然后再像賦值一樣賦給nnn
可以試試A:int,B:longlongA:int,B:long\ longA:int,B:long?long也是一樣的
而第一種寫法AAA是intintint類型的,顯然存不下,所以就爆出去了
解決方法有兩種
第一個就是像第二種寫法一樣直接把變量開成longlonglong\ longlong?long
第二種就是計算時乘以1ll1ll1ll,一般習慣在第一個變量前面加,這樣右邊整個答案只要在longlonglong\ longlong?long范圍內(nèi)都可以存儲
潑水不收
long long n = ( 1 << 30 ) + ( 1 << 30 ) - 1; long long n = ( 1 << 30 ) + 3 - ( 1 << 30 ) - 4; ... long long n = ( 1 << 30 ) + x - ( 1 << 30 ) - ( x + 1 ); //可以試試這種寫法 //x不要帶得太大 //發(fā)現(xiàn)這種寫法一樣可以這是為什么呢??留給dalao們,蒟蒻不懂
蒟蒻bb:
初學C++,學了很多算法
但是對這種知識真的是了解很少,不懂計算機的運算法則
所以經(jīng)常會在各種歪歪扭扭的角(ka)角(ka)落(guo)落(guo)到處爆掉
PS:
Upd–>2020-06-11
老劉好SB哈哈哈哈,寫FWT板題(f[k]+f[k+p]+mod)(f[k]+f[k+p]+mod)%mod(f[k]+f[k+p]+mod)
還不知道為什么錯了,要是f[k]=f[k+p]=mod?1f[k]=f[k+p]=mod-1f[k]=f[k+p]=mod?1
三個加一起就爆intintint了呀,我看了一眼就發(fā)現(xiàn)了哈哈哈哈哈
菜品特套4:內(nèi)存計算
做FMTFMTFMT州區(qū)劃分,給爺調(diào)崩了,一直RERERE,我都以為是被針對了!!
???
???
long long dp[23][1 << 21], g[23][1 << 21], inv[1 << 21];食用說明書食用說明書食用說明書
1GB=1024MB=1024?1024KB=1024?1024?1024B(byte字節(jié))1GB=1024MB=1024*1024KB=1024*1024*1024B(byte 字節(jié))1GB=1024MB=1024?1024KB=1024?1024?1024B(byte字節(jié))
在 C++ 中
intintint類型每個空間是444個字節(jié)
longlonglong\ longlong?long是888個字節(jié)
boolboolbool類型是111個字節(jié)
數(shù)組占用內(nèi)存的計算
①:a[x][y]a[x][y]a[x][y]的空間大小=x?y=x*y=x?y(數(shù)組大小)?4*4?4(轉化為ByteByteByte)/1024/1024/1024(轉化為KBKBKB)/1024/1024/1024(轉化為MBMBMB)
②:直接用sizeof(a)sizeof(a)sizeof(a),這樣算出來的空間占存的單位是byte
看到這里的時候就已經(jīng)明白自己是如何死得死翹翹的了
就以RERERE的數(shù)組大小來舉栗計算
23?(1<<22)=96468992?4(B)/1024=376832(KB)/1024=368MB23*(1<<22)=96468992*4(B)/1024=376832(KB)/1024=368MB23?(1<<22)=96468992?4(B)/1024=376832(KB)/1024=368MB
按照intintint的字節(jié)數(shù)來計算就已經(jīng)如此之大,更何況開的是longlonglong\ longlong?long,內(nèi)存算出來就要×2×2×2
涉及內(nèi)存的一般都是卡你數(shù)據(jù)結構啊,或者狀壓dpdpdp…
我認為學習C++還是有必要掌握這么基本的內(nèi)存計算方法,因為編譯器的不同對數(shù)組的最大忍受也不同,可能編譯能過,但是交上去跑出來是RE,這個時候調(diào)起來就會很崩潰...
菜品特套5:全局變量和局部變量的重復
???
#include <cstdio> int n;void calc() {for( int i = 1;i <= n;i ++ )... }int main() {n = ...return 0; }???
#include <cstdio> int n;void calc() {for( int i = 1;i <= n;i ++ )... }int main() {int n = ...return 0; }食用說明書食用說明書食用說明書
太智障了,這個坑,一點都不想說fa
做的FMT遺失的答案掉的坑,凸(艸皿艸 )
局部變量只在局部內(nèi)有值
全局變量適用于全局
局部內(nèi)可以正確調(diào)用局部變量
局部外的其他版塊一旦涉及到該變量,默認調(diào)用全局
一言以蔽之:局部內(nèi)優(yōu)先調(diào)用局部內(nèi)的變量,次調(diào)用全局變量
所以錯誤寫法中calccalccalc版塊的nnn其實是等于0的,該forforfor循環(huán)根本未被執(zhí)行
報告完畢!
菜品特套6:順序結構&& ||前后順序
???
bool vis[n + 5]; while( x <= n && vis[x] ) x += y;???
bool vis[n + 5]; while( vis[x] && x <= n ) x += y;食用說明書食用說明書食用說明書
順序結構大師上線
在我初學C++的時候就曾經(jīng)犯過這個問題,沒想到時隔多年再次煞筆
由&&∣∣\&\&\ ||&&?∣∣連接的順序結構
一連串的條件限制,程序默認從左往右順次判定
所以在錯誤寫法中,極有可能vis[x]vis[x]vis[x]就已經(jīng)炸出visvisvis的范圍了,看都沒看后面的條件限制
最終導致程序死亡
菜品特套7:scanf(“%s”)與換行符的愛恨情仇
爺爺/奶奶你追的博客,關注的大大更新了
因為真的被玄學到了,所以單獨開了一篇blog來寫
這里直接上鏈接吧
五星菜品⑦
菜品特套8:break
原料來自于此blog題解的第二題
這里不談正解,只考慮用mapmapmap暴力搞的寫法 因為我考場就是純map
???
???
for( int i = 1, x;i <= m;i ++ ) {scanf( "%d", &x );long long ans = 0;bool no = 0;for( int j = 1;j <= x;j ++ ) {cin >> s;if( mp[s] ) ans += mp[s];else { no = 1; break; }}if( no ) printf( "-1\n" );else printf( "%lld\n", ans ); }食用說明書食用說明書食用說明書
想必dalao看一眼就知道咋回事了
沒錯
breakbreakbreak:結束當前循環(huán)
continue:continue:continue:結束當前情況,并不結束當前循環(huán)
舉個栗子
for( int i = 1;i <= n;i ++ )if( i & 1 ) break; for( int i = 1;i <= n;i ++ )if( i & 1 ) continue;breakbreakbreak,i=1i=1i=1就直接結束循環(huán)了,所以時間復雜度只有111
continuecontinuecontinue,iii還是會把nnn以內(nèi)的數(shù)都遍歷一遍,時間復雜度仍為O(n)O(n)O(n)
再多說幾句,break,continue...break,continue...break,continue...這種語句,跟其他語句混用必須打大括號,不認逗號
如果每一條語句之間都是逗號
計算機會一直讀,默認到最后分號出現(xiàn)的位置為一整條語句
所以就不用打大括號
但套上這種專有語句后,就不行了 我也不造為什么
舉個栗子
?
?
for( int i = 1;i <= n;i ++ )if( i & 1 ) { ans ++, p[++ cnt] = i; continue; }?
for( int i = 1;i <= n;i ++ )if( i & 1 ) ans ++, p[++ cnt] = i, continue;
轉回正題
因為我邊讀入邊線性求解,發(fā)現(xiàn)是窮人后就直接breakbreakbreak,導致當前組數(shù)據(jù)壓根沒讀完
再加之這道題是多組數(shù)據(jù),被我中間插斷的數(shù)據(jù)就被我的計算機讀入成為下一組數(shù)據(jù)了
菜品特套9:,;的差距
我以為許久不更新以后就不會寫sb鍋了
???
#include <cstdio> void solve( int x ) {printf( "%d\n", x ); } int main() {int cnt = 1;int pre = ++ cnt; solve( cnt );printf( "%d", pre );return 0; } /* 輸出: 2 2 */???
#include <cstdio> void solve( int x ) {printf( "%d\n", x ); } int main() {int cnt = 1;int pre = ++ cnt, solve( cnt );printf( "%d", pre );return 0; }/* 輸出: 2 */食用說明書食用說明書食用說明書
可能似個人就看出來了,錯誤寫法中intintint變量名的定義和函數(shù)調(diào)用中間用的逗號連接
之前也不是沒犯過因為逗號死掉的問題,這次又中了
逗號連接的在計算機里的默認是一句話
所以計算機將我的函數(shù)調(diào)用理解為了int solve(cnt),然后。。。。p都沒干
菜品特套10:STL的map/set
setsetset:自動去重——解決方法,重載排序
mapmapmap:本質(zhì)也是一個排序的,不然為什么會有unorderd_map??
所以如果傳入的下標是多個元素,必須重載排序,才能編譯成功
并且每一個元素都要參與排序
比如(1,2,3)(1,2,3)(1,2,3),(1,2,4)(1,2,4)(1,2,4)
只比較前兩位參與排序,那么setsetset自動去重了只留下一個,mapmapmap則判斷兩者為一樣的
灰常感謝香香mm的傾情贊助,真是讓吾輩受益匪淺呢!!%%%%
菜品特套11:C++的執(zhí)行順序
前言:是在最近做的線段樹優(yōu)化建圖時碰到的
addedge( u, ++ cnt ); addedge( cnt, ++ cnt ); addedge( v, cnt );這三條語句寫者的想法是,uuu向cntcntcnt點連邊,然后cntcntcnt向++cnt++cnt++cnt(cntcntcnt先自加111)連邊,vvv向cnt+1cnt+1cnt+1連邊
e.g. cnt=1cnt=1cnt=1,uuu向111連邊,111向222連邊,vvv向222連邊
你就可以發(fā)現(xiàn)Dev-c++被卡RE了
因為
c++一條語句其實是從右往左讀的
也就是說在第二條加邊語句中,是先cnt++cnt++cnt++再cntcntcnt與cntcntcnt連邊
這就連出了自環(huán)的無限循環(huán)了
所以必須這么寫
addedge( u, ++ cnt ); addedge( cnt, cnt + 1 ); addedge( v, ++ cnt );這也能說明,有的時候我們會像下面這么連續(xù)賦值
int a, b, c, d; a = b = c = d = 419;先執(zhí)行d=419,然后c=d,接著b=c,最后a=b,成功賦值四個變量
菜品特套12:順次處理字符讀入
最近都有碰到字符串讀入的處理
眾所周知,只有空格和換行是非常頭疼的
而且現(xiàn)在隨著版本的更新,gets()已經(jīng)不允許使用了(但是它的功能真的很舒服啊,可以讀入空格和換行,哎),可以試試fgets(),但建議還是別了吧
一般讀入字符串的方法如下
- 一個一個字符地讀,ch=getchar(),scanf("%c",&ch)
好處自然是可以通過條件語句判斷空格和換行,做出相應舉措 - 一個字符串一個字符串地讀,scanf("%s",s),cin>>s
但都是遇到空格或者換行就直接結束了,便于我們直接處理不要空格和換行的題目
但是博主最近的問題是,需要空格和換行,那么就選擇了一個一個字符地讀
結果總是忘記最后一個字符串是留下來未操作的,因為后面是空,不能觸發(fā)處理一個字符串的結束條件
經(jīng)常最后一個字符串被遺忘,導致出錯丟分
菜品特套13:傳地址的動態(tài)開點
最近做了兩道題,是需要可持久化字典樹的。
而可持久化標準需要動態(tài)開點,所以大家都習慣于直接把數(shù)組的地址傳過去,這樣就直接改了數(shù)組。
但是字典樹的可持久化就不要傳了。
void insert( int lst, int &now, char s ) {now = ++ cnt; t[now] = t[lst];for( int i = 1;i <= n;i ++ ) {int c = s[i] - 'a';t[now].son[c] = ++ cnt;now = t[now].son[c];lst = t[lst].son[c];t[now] = t[lst];} } insert( root[i - 1], root[i], s[i] );受到可持久化字典樹的影響實在太大了。
上面的寫法完全是錯誤的,因為 nownownow 從始至終都帶的是地址,所以看似我們走了 nownownow 的兒子邊,但是其實一直都是 root[i]root[i]root[i] 的編號在自加。
只有 lstlstlst 版本的字典樹一直在正確的走。
所以字典樹的就不要傳地址了,直接改原數(shù)組得了。
void insert( int lst, int now, char s ) {root[now] = ++ cnt; now = root[now];lst = root[lst];t[now] = t[lst];for( int i = 1;i <= n;i ++ ) {int c = s[i] - 'a';t[now].son[c] = ++ cnt;now = t[now].son[c];lst = t[lst].son[c];t[now] = t[lst];} } insert( i - 1, i, s[i] );菜品特套14:異或判斷相等的偷懶
因為本人的碼風和個人喜好問題,比起來 != 我更喜歡 ^ 而且少占一個字符。
眾所周知 x^x=0,所以我很喜歡,if(a^b) ... 這種寫法。
這倒是沒什么問題,因為 if-else 這種判斷句又是 bool\text{bool}bool 類的,只認 0/10/10/1。
但是寫多了就以為本身運算就是個 0/10/10/1 的返回。
比如我的本意是如果 x≠yx\ne yx?=y 就 +1+1+1,否則 +0+0+0。
寫代碼就容易寫成 ans+=(x^y)。
這簡直就是大錯特錯!現(xiàn)在的 x^y 明顯是個運算了,而不是 [x^y] 的條件判斷。
不如老老實實寫 != ,因為這個真的很難調(diào),思維進入一個誤區(qū)跳出來很困難的欸。
總結
以上是生活随笔為你收集整理的世界五星级大厨经典菜品集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第八周项目5-定期存款利息计算器
- 下一篇: 【输入法】Rime-中州韵 基本设置 附