Sprout 2013 Solution2. 題目選單 PROBLEMS
By Andy, 129623.
Problem # Title Hi-score
1 a plus b 2/2
2 寂寞的手裏劍 10/10
3 可憐的動物管理員 0/10
4 覺醒吧!完美蚖! 10/10
5 天啊!是南啼! 10/10
6 括弧字串 10/10
7 撈哥慨慨 10/10
8 文章查詢 8/10
9 Cat~MeowRio~ 10/10
Total 70/82
5. CODE FOR #1
By Andy, 129623.
#include<iostream>
using namespace std;
int main(){
int a,b;
cin>>a>>b;
cout<<a+b<<endl;
return 0;
}
7. CONCEPT
列舉觀察
n=1, m=0, ans=1
n=2, m=1, ans=3
n=3, m=3, ans=6
n=4, m=6, ans=10
難道答案是
𝑛 𝑛+1
2
?
By Andy, 129623.
9. CODE FOR #2
By Andy, 129623.
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
if(n<=2)cout<<n+(n*(n-1)/2)<<endl;
else cout<<4*n-6<<endl;
return 0;
}
12. 解答排序(SOLUTION SORTING)
大魔王來了,解答出來怎麼排序?
1. 解答對(x1,y1)、(x2,y2)排序
注意到格子只能上下交換、左右交換
所以一定有一個座標值(x或y)是相同的!
因此,可以做一個「通吃的解法」寫成
𝑎𝑛𝑠 = min(𝑥1, 𝑥2) , min y1,y2 , min(𝑥1, 𝑥2) ,max(y1,y2)
2. 解答之間排序
我知道排序可以用sort(),可是有四個維度要怎麼排?
每個維度都是1~8,可以把它們壓成四位數再排!
輸出的時候再解開就好。
排序之後,判斷重複就方便了!
By Andy, 129623.
13. CODE FOR #3
By Andy, 129623.
#include<iostream>
#include<algorithm>
using namespace std;
char t[11][11];
//解答
int ans[1000],solcnt=0;
//確認並儲存(tx,ty)->(nx,ny)解答對
void check(int x,int y,int dir,int
ndir){
int tx=x,ty=y;
switch(dir){
case 1:tx--;ty--;break;
case 2:tx--;ty++;break;
case 3:tx++;ty--;break;
case 4:tx++;ty++;break;
case 5:tx-=2;break;
case 6:ty+=2;break;
case 7:tx+=2;break;
case 8:ty-=2;break;
}
//如果不合法就退出
if(tx>8||ty>8||tx<=0||ty<=0)return;
int nx=tx,ny=ty;
switch(ndir){
case 1:nx--;break;
case 2:nx++;break;
case 3:ny--;break;
case 4:ny++;break;
}
if(t[x][y]==t[tx][ty]){
//為解答編碼成4位數字,左上角先存
ans[solcnt++]=100*(10*min(tx,nx)+min(
ty,ny))+10*max(tx,nx)+max(ty,ny);
}
}
注:dir: 1左上 2右上 3左下 4右下
5上x2 6右x2 7下x2 8左x2
ndir: 1上2下3左4右
14. CODE FOR #3 CONT.
By Andy, 129623.
void sort(){
sort(ans,ans+solcnt);
//避免輸重複解答
int last=ans[0];
for(int i=1;i<solcnt;i++)
if(ans[i]==last){
ans[i]=-1;
}else{
last=ans[i];
}
}
void print(){
for(int i=0;i<solcnt;i++){
if(ans[i]==-1)continue;
int from[2]={(ans[i]/100)/10,(ans[i]/100)%10};
int to[2]={(ans[i]%100)/10,(ans[i]%100)%10};
cout<<"("<<from[0]<<","<<from[1]<<"),";
cout<<"("<<to[0]<<","<<to[1]<<")"<<endl;
}
}
15. CODE FOR #3 CONT.
By Andy, 129623.
int main(){
//先鋪1層外圍的#,表示沒有東西
for(int i=0;i<=10;i++)for(int j=0;j<=10;j++)t[i][j]='#';
//輸入
for(int i=1;i<=8;i++)for(int j=1;j<=8;j++)cin>>t[i][j];
//依序掃每一格上下左右是否有相鄰
for(int i=1;i<=8;i++){
for(int j=1;j<=8;j++){
//只要往下往右掃就可
if(t[i][j]==t[i+1][j]){
check(i,j,1,4);
check(i,j,2,3);
check(i+1,j,3,4);
check(i+1,j,4,3);
check(i,j,5,2);
check(i+1,j,7,1);
}
if(t[i][j]==t[i+2][j]){
check(i,j,3,4);
check(i,j,4,3);
}
16. CODE FOR #3 CONT.
By Andy, 129623.
if(t[i][j]==t[i][j+1]){
check(i,j,1,2);
check(i,j+1,2,2);
check(i,j,3,1);
check(i,j+1,4,1);
check(i,j,8,4);
check(i,j+1,6,3);
}
if(t[i][j]==t[i][j+2]){
check(i,j,2,2);
check(i,j,4,1);
}
}
}
sort();
print();
return 0;
}
18. CONCEPT
乍看之下好像很複雜
一邊轉一邊改,還不如先轉轉看再改!
因為只能整段旋轉,其實可以直接掃:
ATCGATCG
TCGATCGA
CGATCGAT
GATCGATC …
每次轉一位,看看有幾個基因需要改,統計最小值即可!
設字串長度為n,左旋轉a次可以替換成右旋轉n-a次!
轉a位可以想成迴圈變數i加上a,字串取超過的時候從頭繼續取就好
可以用取餘數(%)完成這個操作!
By Andy, 129623.
19. CODE FOR #4 (CORE FUNCTIONS)
By Andy, 129623.
string s1,s2;
char getS1(int index){
//超過就從頭開始取
return s1[index%s1.size()];
}
char getS2(int index){
//超過就從頭開始取
return s2[index%s2.size()];
}
20. CODE FOR #4 CONT.
By Andy, 129623.
int main(){
cin>>s1>>s2;
int ans=-1,len=s1.size();
for(int begin=0;begin<len;begin++){
//定義兩種操作
int opa=min(begin,len-begin),opb=0;
//比較差異
for(int i=0;i<len;i++)opb+=getS1(begin+i)!=getS2(i);
//更新最優解
if(ans==-1)ans=6*opa+4*opb;
ans=min(ans,6*opa+4*opb);
}
cout<<ans;
return 0;
}
23. CODE FOR #5
By Andy, 129623.
#include<iostream>
using namespace std;
bool match(char c){
return c=='X'||c=='D'||c=='r'||c=='z';
}
int main(){
string a,b;
int x=0,y=0;
getline(cin,a);
getline(cin,b);
for(int i=0;i<a.size();i++)x+=match(a[i]);
for(int i=0;i<b.size();i++)y+=match(b[i]);
if(x<=y)cout<<"Yes!!!";else cout<<"NO QAQ";
return 0;
}
25. CONCEPT
想想看自己平常是怎麼看括號合不合法?
合法:(())((()))
合法:(((()))())))
不合法:())(())()
Why? 因為它有個孤獨的右括號!
你怎麼知道它是孤獨的?
因為它前面沒有足夠的左括號!(這是關鍵)
所以,從頭開始數左括號和右括號,一旦右括號比左括號
多就不用繼續比了!
或者可以簡化:令一個變數初始為0,遇到左括號+1,遇到右括號-1,
但如果不夠減就可以停了!
最後當然要判斷左括號和右括號一不一樣多。
By Andy, 129623.
27. CODE FOR #6
By Andy, 129623.
#include<iostream>
using namespace std;
int main(){
string s;
while(getline(cin,s)){
int cnt=0,flag=1;
for(int i=0;i<s.size()&&flag;i++){
if(s[i]=='(')cnt++; else {
if(cnt<=0)flag=0; else cnt--;
}
}
if(cnt)flag=0;
cout<<(flag?"Yes":"No")<<endl;
}
}
30. CONCEPT
既然只跟直徑有關,就不需要管圓心了
邊界一定要是整數,在整數點之間沒有比較好
顯然可以枚舉起點(自xi最小值到最大值)再統計區間中的女
生個數,複雜度O(n*(max(xi)-min(xi)))
在xi範圍很大時,太慢了!
還可以怎麼做?
有一個邊界一定要在女生上,否則像套橡皮筋一樣,真正能抓到女
生的範圍就變小了!
所以枚舉的起點就只有k個,複雜度降為O(kn)
統計優化:可以發現其實先把陣列排好序可以節省很多時間!
做二分搜,可以讓複雜度降為O(klogn),不過循序已經夠好了。
By Andy, 129623.
31. CODE FOR #7
By Andy, 129623.
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int n,k;
cin>>n>>k;
int a[n];
for(int i=0;i<n;i++)cin>>a[i];
//排序
sort(a,a+n);
int ans=0;
//窮舉左邊界
for(int i=0;i<n;i++){
int l=a[i],r=l+k,cnt=0;
for(int j=i;j<n;j++){
if(a[j]>=l)
if(a[j]<=r)cnt++; else break;
}
ans=cnt>ans?cnt:ans;
if(r>a[n-1])break;
}
cout<<ans;
return 0;
}
34. CODE FOR #8 (CORE FUNCTIONS)
By Andy, 129623.
#include<iostream>
using namespace std;
//判斷是否相等,大小寫視為相同
bool isSame(char a,char b){
//先都轉換成大寫
if(b>='a'&&b<='z')
b=b-'a'+'A';
if(a>='a'&&a<='z')
a=a-'a'+'A';
return a==b;
}
bool isAlpha(char x){
return (x>='a'&&x<='z')||(x>='A'&&x<='Z');
}
35. CODE FOR #8 CONT.
By Andy, 129623.
int main(){
int has=0;
string s,tar;
int
strBegin[1000],printed[1000],sbcnt=1;
getline(cin,s);
cin>>tar;
strBegin[0]=printed[0]=0;
//記錄所有開始 (類似split作用)
for(int i=0;i<s.size();i++)
if(s[i]==‘.’){
//.->空白->下一句開頭
strBegin[sbcnt]=i+2;
printed[sbcnt]=0;
sbcnt++;
}
//末句不算,避免越界
strBegin[sbcnt--]=0;
for(int i=0;i<s.size();i++){
int offset=0,flag=0;
//如果首字元(前字元為-1),前面必定
不是字母,傳回*
char prevChar=(i!=0)?s[i-
1]:'*';
char nextChar=(i+tar.size()
<s.size())?s[i+tar.size()]:'*';
if(!isAlpha(prevChar)&&!isAlpha(n
extChar))
while(isSame(tar[offset],s[i+offs
et])){
if(offset==tar.size()-1)flag=1;
offset++;
}
else flag=0;
36. CODE FOR #8 CONT.
By Andy, 129623.
if(flag){
has=1;
int jj;
for(jj=0;jj<sbcnt;jj++){
if(i<strBegin[jj])break;
}
if(!printed[jj]){
for(int j=strBegin[jj-1];s[j-1]!='.';j++){
cout<<s[j];
}
cout<<endl;
printed[jj]=1;
}
}
}
if(!has)cout<<"None.";
return 0;
}
38. CONCEPT
規模不是很大(𝑛 ≤ 20),用O(2n)再剪枝就很快了。
可以用DFS(Depth-First Search,深度優先走訪)來做,若
n的硬幣依序考慮,第k個硬幣重量Wk,且 𝑓(𝑘, 𝑊)為前k個
硬幣所能得到的最佳解,遞迴關係可以列如下:
𝑓 𝑘, 𝑊 =
0,當𝑘 = 0
0,當𝑊 < 0
max 𝑓 𝑘 − 1, 𝑊 − 𝑊𝑘 + 𝑊𝑘, 𝑓 𝑘 − 1, 𝑊 , 𝑊 ,其他情形
沒那麼複雜,其實max裡就是選與不選這兩種而已!
而其他的情形就是邊界條件(boundary condition),你不會
希望無窮遞迴的!
By Andy, 129623.
40. CODE FOR #9
By Andy, 129623.
#include<iostream>
using namespace std;
int n,wmax,ans=0;
int coin[30];
void dfs(int dep,int sum){
if(sum>wmax)return;
if(dep==n){
ans=sum>ans?sum:ans;
return;
}
dfs(dep+1,sum+coin[dep]);
dfs(dep+1,sum);
}
int main(){
cin>>n>>wmax;
for(int i=0;i<n;i++)cin>>coin[i];
dfs(0,0);
cout<<ans;
}