學校教的程式語言課是用C,而C++我是自學,目前對於C++字串的使用還不是很熟練,所以想藉由這題熟悉一下用法。 getline(cin, string)可以讀取一整行含空白的string,而string.substr(a, b)這個函式則是從string中第a個字元開始擷取b個字元。 這題蠻簡單的,就是將第一行的輸入去掉空白,分別放入vector裡,然後直接輸出”第二行的內容, vec[i]”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> #include <string> #include <vector> using namespace std;int main () { int i, pi=0 , j; string name, greet; vector<string> vec; getline (cin, name); getline (cin, greet); for (i=0 ;i<name.size ();i++){ if (name[i]==' ' ){ vec.push_back (name.substr (pi,i-pi)); pi=i+1 ; } } vec.push_back (name.substr (pi,name.size ())); for (i=0 ;i<vec.size ();i++){ cout<<greet<<", " <<vec[i]<<endl; } return 0 ; }
做這題主要是想熟悉python操作字串的用法,在解題報告中有人只用一行就完成所有事情,而且是沒有用分號的情況下,真的是大佬,像我這樣的初學者只能縮到3行,而且也盡量讓每一行都做很多事。這次的解題步驟就用一行一行來講解。
第一行:用input()讀取一個string,ord(c)將該string的每個字元轉成ASCII碼,然後用original這個list儲存,一個字元的ASCII碼就是一個element。 第二行:讀取original,將裡面的每個元素的ASCII碼減7,並透過chr()轉成char,然後用after這個list儲存,一個字元就是一個element。 第三行:利用’’.join()這招將after轉成string並輸出。
1 2 3 original = [ord (c) for c in input ()] after = [chr (c-7 ) for c in original] print ('' .join(after))
在Python裡,string的index還能有如此操作:
[A:B:C] A指的是string的起始字元(不輸入則預設0) B指的是string的結束字元(不輸入則預設為string的最後一個字元的位置) C指的是字元取完後要往後幾格(不輸入則預設為1) 然後欄位C也能塞負整數,這樣得到的字元順序也是顛倒的。
註:list也能這樣操作
1 2 3 s=input () if s==s[::-1 ]:print ('yes' )else :print ('no' )
這是我原本的作法,讀到整數後,先判斷是不是0,然後再拆成一個一個的位數並放到list,最後將list倒著輸出。這個解法幾乎是最慢的解法,只差我沒有把list顛倒後合併成一個整數,然後輸出整數而已。不過如果今天我是用C或C++來解這題,我還真只能這樣解。
1 2 3 4 5 6 7 8 n=int (input ()) d=[] if n==0 :print ('0' )else : while n%10 ==0 :n//=10 while n>0 : d.append(n%10 );n//=10 for i in range (len (d)):print (d[i],end='' )
看到python-94狂-2行解決 ,真的是簡單又粗暴。在input()後面加上[::-1],讓輸入的string直接變顛倒的。外面包住的int()再將這個顛倒的string變成整數,同時也解決最大為數為0的問題,一行就完成所有的事情。
1 2 n=int (input ()[::-1 ]) print (n)
其實我一直看不懂最受歡迎的「課程組合」的人數到底怎麼求出來的,我一開始以為是如果最多人的組合只有一個,就輸出那個人數,然後有超過一個組合最多人,就輸出有多少組,結果看完別人的code才知道原來是最多人數x符合的組合 ,怎麼想都怪怪的。
解完這題,爬了別人的code 才發現,我可以直接輸入string,然後排序完就能拼起來了,我還多了一個整數轉成字串的動作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <bits/stdc++.h> using namespace std;int main () { int n,num[5 ],i,h; while (cin >> n && n){ map<string, int > cbList; for (h=0 ;h<n;h++){ for (i=0 ;i<5 ;i++){ cin >> num[i]; } sort (num, num+5 ); string cb="" ; for (i=0 ;i<5 ;i++){ cb += to_string (num[i]); } if (cbList.count (cb)){ cbList[cb]++; } else { cbList[cb]=1 ; } } int mx=0 , ans=0 ; map<string, int >::iterator j; for (j=cbList.begin (); j!=cbList.end (); j++){ if ( (j->second) > mx ){ mx = j->second; } } for (j=cbList.begin (); j!=cbList.end (); j++){ if ( (j->second) == mx ){ ans += mx; } } cout << ans << "\n" ; } return 0 ; }
原本是打算讓start指向第一個字母,end指向最後一個字母,但想到測資可能會有雞巴的情況,比如兩個單字中間的空格不只一個,我就索性讓start,end都指向空白處。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <bits/stdc++.h> using namespace std;int main () { ios::sync_with_stdio (false ); string key, s; getline (cin, key); getline (cin, s); s = s + " " ; int kl = key.size (), sl = s.size (), i; for (i=0 ;i<kl;i++){ if ('A' <= key[i] && key[i] <= 'Z' ){key[i] += 32 ;} } for (i=0 ;i<sl;i++){ if ('A' <= s[i] && s[i] <= 'Z' ){s[i] += 32 ;} } int start = -1 , end = 0 , cnt = 0 , first; for (i=0 ;i<sl;i++){ if (s[i] == ' ' ){ end = i; if (end-start-1 == kl){ int same = 1 ; for (int jk=0 ,js=start+1 ; jk<kl ; jk++,js++){ if (key[jk] != s[js]){ same = 0 ;break ; } } if (same){ if (!cnt){first = start+1 ;} cnt++; } } start = i; } } if (!cnt){cout << "-1\n" ;} else {cout << cnt << " " << first << "\n" ;} return 0 ; }
以前只要是用C,或是C++處理字串,我都是馬上先宣告string,這次想挑戰不用string儲存完成這題,有點麻煩,因為還要多判斷換行符號,如果是用string做,只需要讀到EOF然後直接跳出來就好了,不過不宣告string這樣比較省記憶體,還是有好處的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <stdio.h> #include <ctype.h> int main () { char c; int cnt=0 , rec=0 ; while (scanf ("%c" ,&c)!=EOF){ if (isalpha (c)){rec=1 ;} else { if (rec){cnt++;rec=0 ;} } if (c=='\n' ){ printf ("%d\n" ,cnt); cnt=0 ; } } if (cnt){printf ("%d\n" ,cnt);} return 0 ; }
上面的b969也有遇到要去除空白的情況,這次我想換個方法,用stringstream。也順便弄了一個給C++的加速組合包。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <bits/stdc++.h> #define speedup ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) using namespace std;int main () { speedup; int t, i; string team, judge; cin >> t; cin.ignore (); for (i=1 ;i<=t;i++){ getline (cin, team); getline (cin, judge); cout << "Case " << i << ": " ; if (team == judge){cout << "Yes\n" ;} else { stringstream ss; string s, tmp="" ; ss.clear (); ss << team; while (ss >> s){tmp += s;} if (tmp == judge){cout << "Output Format Error\n" ;} else {cout << "Wrong Answer\n" ;} } } return 0 ; }
這題本來不打算放的,不過看到討論區某些人的思路,覺得還挺特別,就照著做了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 n = int (input ()) for i in range (n): s = input () a = 'one' if len (s) != 3 : print (3 ) else : diff = 0 for j in range (3 ): if s[j] != a[j]: diff += 1 if diff > 1 : print (2 ) else : print (1 )
這題的輸出格式蠻難搞的,而且範例輸出的Column、|、__,根本不用輸出。
我的想法是用兩個變數x,y,x存這個字元的編碼,y存上一個字元的編碼,如果xy不一樣,而且x的值是在1~6之間,我們就放入num,當num都放滿了,直接跳出迴圈。
然後要注意一下範例測資裡的SCHAEFER,因為C跟S的編碼一樣,所以這個編碼2就不會被輸出。這就是為什麼我在初始化的時候先令y為第一個字母的編碼,然後跑迴圈就可以從第二個字母開始檢查。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <stdio.h> #include <string.h> int code (char c) { switch (c){ case 'B' : case 'P' : case 'F' : case 'V' : return 1 ; case 'C' : case 'S' : case 'K' : case 'G' : case 'J' : case 'Q' : case 'X' : case 'Z' : return 2 ; case 'D' : case 'T' : return 3 ; case 'L' : return 4 ; case 'M' : case 'N' : return 5 ; case 'R' : return 6 ; default : return 0 ; } } int main () { char s[25 ]; puts (" NAME SOUNDEX CODE" ); while (scanf ("%s" ,s) != EOF){ int sl=strlen (s),i,num[3 ]={0 },cnt=0 ,x,y=code(s[0 ]); for (i=1 ;i<sl;i++){ x = code(s[i]); if (x!=y && x!=0 ){num[cnt]=x;cnt++;} y = x; if (cnt >= 3 ){break ;} } printf (" %-25s%c" ,s,s[0 ]); for (i=0 ;i<3 ;i++){ printf ("%d" ,num[i]); } printf ("\n" ); } printf (" END OF OUTPUT" ); return 0 ; }
因為每筆輸入都會有空格,所以用getline讀整行字串,再用stringstream去掉空白並分割。分完後只需用長度來判斷該做什麼事即可。不過題目舉的例子11011我覺得不好,因為它是palindrome,這讓我搞錯進位的方向。舉1011為例,我以為是1x8 + 0x4 + 1x2 + 1x1,結果題目要的是1x8 + 1x4 + 0x2 + 1x1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <bits/stdc++.h> #define speedup ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) using namespace std;int main () { speedup; string s,t; while (getline (cin, s) && s != "~" ){ int flag = 0 , cnt = 0 , i, ans = 0 ; stringstream ss; ss << s; while (ss >> t && t != "#" ){ int tl = t.length (); if (tl == 1 ){flag = 1 ;} else if (tl == 2 ){flag = 0 ;} else { for (i=0 ;i<tl-2 ;i++){ ans = ans*2 + flag; } } } cout << ans << "\n" ; } return 0 ; }
因為每一次操作都會影響所有的連續空白片段,所以我們只需要先得到最大的 連續空白片段的 長度 ,然後再算出要除以2幾次才會變一個空白,這個次數就是解答。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <bits/stdc++.h> #define speedup ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) using namespace std;int main () { speedup; string s; while (getline (cin, s)){ int spl=0 ,mxspl=0 ,sl=s.length (),i; for (i=0 ;i<sl;i++){ if (s[i] == ' ' ){spl++;} else { if (spl){ if (spl > mxspl){mxspl = spl;} spl = 0 ; } } } int t=0 ,tmp; while (mxspl > 1 ){ tmp = mxspl%2 ; mxspl = mxspl/2 + tmp; t++; } cout << t << "\n" ; } return 0 ; }
這題我看到討論區告訴大家不要害怕TLE的時候,就先用C++躍躍欲試,結果我明明都幫IO端加速了,還是TLE。不知道是不是因為一直在string、stringstream、int之間做轉換很耗時。後來用C就只有用int array運算,速度真的快很多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <bits/stdc++.h> #define speedup ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) using namespace std;int main () { speedup; string s; while (cin >> s){ int st=1 ,i,j,sl=s.length (); while (st <= 10000 ){ stringstream ss; string yf="" ; for (i=0 ;i<sl;i++){ ss << s[i]-65 +st; } yf = ss.str (); int yl=yf.length (),t; string tmp="" ; for (i=0 ;i<yl-3 ;i++){ int yfl = yf.length (); for (j=0 ;j<yfl-1 ;j++){ t = yf[j] + yf[j+1 ] - 48 ; if (t >= 58 ){t -= 10 ;} tmp = tmp + (char )t; } yf = tmp;tmp = "" ; cout << yf << "\n" ; } if (yf == "100" ){ cout << st << "\n" ; break ; } st++; } if (st > 10000 ){ cout << ":(\n" ; } } return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <stdio.h> #include <string.h> int main () { char s[15 ]; while (scanf ("%s" ,s) != EOF){ int st=1 ,i,j,sl=strlen (s); while (st <= 10000 ){ int ss[50 ],cnt=0 ,tmp; for (i=sl-1 ;i>=0 ;i--){ tmp = s[i] - 65 + st; while (tmp > 0 ){ ss[cnt] = tmp%10 ; tmp /= 10 ; cnt++; } } int cntt = cnt-3 , cnto = cnt-1 ; for (i=0 ;i<cntt;i++){ for (j=0 ;j<cnto;j++){ ss[j] = (ss[j] + ss[j+1 ]) % 10 ; } ss[j] = 0 ; cnto--; } if (ss[0 ]==0 && ss[1 ]==0 && ss[2 ]==1 ){ printf ("%d\n" ,st); break ; } st++; } if (st > 10000 ){ printf (":(\n" ); } } return 0 ; }
終於又有上榜的機會,而且還是第五名!
這題我是先用map儲存對照表,然後一次讀整行的1337文字,透過stringstream分割空白,再丟到對照表裡看能不能對照,如果可以就轉換輸出,如果找不到直接輸出本體。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <bits/stdc++.h> #define speedup ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) using namespace std;int main () { map<string, string> dict; string s,a,b,c; cin >> s; while (getline (cin, s) && s!="[1337]" ){ int sl = s.length (),i; a="" ;b="" ; for (i=0 ;s[i]!=':' ;i++){ a += s[i]; } for (i+=1 ;i<sl;i++){ b += s[i]; } dict[a] = b; } while (getline (cin, s) && s!="[3ND]" ){ stringstream ss; map<string, string>::iterator it; ss << s; while (ss >> c){ int find = 0 ; for (it=dict.begin () ; it!=dict.end () ; it++){ if ((it->first) == c){ cout << it->second; find = 1 ; break ; } } if (!find){cout << c;} cout << " " ; } cout << "\n" ; } return 0 ; }
我的策略是遇到要水平翻轉的(R)直接用字串特性[::-1]將整行顛倒、遇到要垂直翻轉的(I)直接用迴圈特性從下往上輸出、遇到兩個全都要的(IR)就兩個特性一起用,python就是這麼爽。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 try : while 1 : a = input ().split() x = int (a[1 ]) y = int (a[2 ]) sky = [[0 ]*x for i in range (y)] for i in range (y): sky[i] = input () print (a[0 ]) if a[3 ]=='R' : for i in range (y): print (sky[i][::-1 ]) elif a[3 ]=='I' : for i in range (y-1 ,-1 ,-1 ): print (sky[i]) elif a[3 ]=='IR' : for i in range (y-1 ,-1 ,-1 ): print (sky[i][::-1 ]) except EOFError: pass
恩,又學了一些stringstream的用法,這次還加入十六進位的轉換。也因為如果只轉hex,輸出的字母是小寫的,所以用setiosflags(ios::uppercase)把字母轉成大寫輸出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <bits/stdc++.h> #define speedup ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) using namespace std;int main () { speedup; string s; while (cin>>s && s[0 ]!='-' ){ stringstream ss; string num="" ; int n,sl=s.length (),i; if (s[0 ]=='0' ){ for (i=2 ;i<sl;i++){ num+=s[i]; } ss<<num; ss>>hex>>n; cout<<dec<<n<<"\n" ; } else { ss<<s; ss>>n; cout<<"0x" ; cout << setiosflags (ios::uppercase) << hex << n << "\n" ; } } return 0 ; }
這題的輸出格式蠻難搞的,尤其是’ + ‘、’ - ‘,為了這個空白運算符,我多加了很多判斷式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <stdio.h> #include <stdlib.h> int main () { int coe[9 ],i,first; while (scanf ("%d" ,&coe[0 ])!=EOF){ for (i=1 ;i<9 ;i++){scanf ("%d" ,&coe[i]);} int allZero=1 ,first=0 ; for (i=0 ;i<9 ;i++){ if (coe[i]){allZero=0 ;break ;} } if (allZero){ printf ("0\n" ); continue ; } for (i=0 ;i<9 ;i++){ if (coe[i]){ if (first){ if (coe[i]>0 ){printf (" + " );} else {printf (" - " );} } first++; if (8 -i>=1 ){ if (coe[i]==1 ){printf ("x" );} else if (coe[i]==-1 ){ if (first>1 ){printf ("x" );} else {printf ("-x" );} } else { if (coe[i]>0 ){printf ("%dx" ,coe[i]);} else { if (first>1 ){printf ("%dx" ,coe[i]*-1 );} else {printf ("%dx" ,coe[i]);} } } } else { if (coe[i]>0 ){printf ("%d" ,coe[i]);} else { if (first>1 ){printf ("%d" ,coe[i]*-1 );} else {printf ("%d" ,coe[i]);} } } if (8 -i > 1 ){printf ("^%d" ,8 -i);} } } printf ("\n" ); } }
封面圖源:Pixiv