TEXT 1:Telephone 点击打开链接
本題主要考查了簡單的字符串處理,當然也可以用hash+排序來解决。我最初考慮到用hash來儲存數據,但想到此題數據較小,且字串長度及字符串的變化比較簡單,沒必要用hash大動干戈(當然,也怕自己寫錯),就直接採用sort排序+兩for迴圈暴力解决問題。
不過也由此發現自己關於hash方面程式碼能力還有所欠缺。一遇到一些字串處理的題就首選暴力。雖然有時候可以僥倖AC,但hash的作用不容小覷,自己需要對hash再加鞏固。
以下是自己的暴力代碼:
- #include<iostream>
- #include<cstdio>
- #include<cstdlib>
- #include<algorithm>
- #include<cmath>
- #include<cstring>
- #include<string>
- using namespace std;
- struct node{
- int zhi,cfcs;
- }same[200020];
- int n,len,tot,all;
- char s[17];
- int num[100010];
- int alpha[26]={2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,0,7,7,8,8,8,9,9,9,0};
- int main()
- {
- freopen("telephone.in","r",stdin);
- freopen("telephone.out","w",stdout);
- ios::sync_with_stdio(false);
- cin.tie(NULL);
- scanf("%d\n",&n);
- int m=n;
- memset(same,0,sizeof(same));
- while(n--)
- {
- gets(s);
- len=strlen(s);
- tot=1;
- for(int i=0;i<len;i++)
- {
- if(s[i]!='-')
- {
- int x;
- if((s[i]-48)>=0&&(s[i]-48)<=9) x=(s[i]-48);
- else x=alpha[s[i]-65];
- for(int j=tot;j<7;j++)
- x*=10;
- num[n]+=x;
- tot++;
- }
- }
- }
- sort(num,num+m);
- all=1;
- for(int i=0;i<m;i++)
- {
- if(num[i]==num[i+1])
- {
- if(same[all-1].zhi!=num[i])
- {
- same[all].zhi=num[i];
- same[all].cfcs++;
- all++;
- }
- else
- same[all-1].cfcs++;
- }
- }
- if(all>1)
- {
- for(int i=1;i<all;i++)
- {
- char ch[10];
- sprintf(ch,"%d",same[i].zhi);
- for(int j=0;j<=2;j++) cout<<ch[j];
- cout<<"-";
- for(int j=3;j<=6;j++) cout<<ch[j];
- cout<<" "<<same[i].cfcs+1<<endl;
- }
- }
- else printf("No duplicates.\n");
- return 0;
- }
TEST 2: 數對個數 点击打开链接
本題限制了空間大小,然而我並不會算。。。
所以最開始定義數組的時候便定義太大了:
int tot[10000000][2];
但後來發現,改成如下在OJ上就AC了:
int tot[1000000][2];
不過這也反映了我在一些基本問題(如計算空間、計算時間複雜度。。。)上的問題。雖然問題都體現在代碼的細節上,但是在NOIP甚至是NOI上都是非常致命的錯誤。
另外,解决此題可以採用很多方法,比如樸素算灋、二分、隊列等。我採用了隊列,先將數據排序,然後枚舉每個數位,將重複的數記錄下來,以及隊列中出現的數用tot[1000000][1]標記;然後進行第二次迴圈查找,
並且有num[tot[ab[i]][1]]做相同數位的標記,所以實際for迴圈的次數遠遠小於所有的數位總數。
而此題還可以用二分解决,用二分來查找a-b=c中的b。我最初也想過用二分甚至hash來查找b,但最後還是採用了數組num、tot[1000000][2]和一個變數all來判斷和查找,雖然在速度上比二分查找快很多,但是對於空間的利用是很低的,囙此容易超容。
這是我自己寫的:
用二分查找:
所以顯而易見,二分在空間上還是占了優勢。
但是也反映了我在空間計算上還有些不足,而對於暴力和先進算灋之間的選擇上,則最好要發揮解决關鍵問題上各自的優勢。
總代碼如下:
- #include<iostream>
- #include<cstdio>
- #include<cstdlib>
- #include<algorithm>
- #include<cmath>
- #include<cstring>
- #include<string>
- using namespace std;
- int num[200020];
- int n,c,all;
- int ab[200020];
- int tot[1000000][2];
- long long ans=0;
- int main()
- {
- freopen("dec.in","r",stdin);
- freopen("dec.out","w",stdout);
- memset(num,0,sizeof(num));
- ios::sync_with_stdio(false);
- cin.tie(NULL);
- cin>>n>>c;
- for(int i=1;i<=n;i++) cin>>ab[i];
- sort(ab+1,ab+1+n);
- all=1;
- for(int i=1;i<=n;i++)
- {
- if(tot[ab[i]][0]==0)tot[ab[i]][0]=1;
- if(ab[i]==ab[i+1])
- {
- if(tot[ab[i]][0]!=2)
- {
- tot[ab[i]][0]=2;
- tot[ab[i]][1]=all;
- num[all]++;
- all++;
- }
- else num[all-1]++;
- }
- }
- for(int i=1;i<=n;i++)
- {
- int aa=1,bb=1;
- if(tot[c+ab[i]][0]>0)
- {
- if(tot[ab[i]][0]==2) aa+=num[tot[ab[i]][1]];
- if(tot[ab[i]+c][0]==2) bb+=num[tot[ab[i]+c][1]];
- ans+=aa*bb;
- }
- i+=num[tot[ab[i]][1]];
- }
- cout<<ans<<endl;
- return 0;
- }
TEST 3:分配教室 点击打开链接
最初想這道題的時候想法與ly的類似,但是我是將同樣一類的人合併再遞推的,所以出現了一些WA。當時有一點蒙,再加上不想改程式碼了,於是强加了一個不可靠的暴力,最初的代碼如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
int n,m;
int peo[2600];
int head1,head2;
int jia=0,yi=0,ans=1;
int samea[2501],sameb[2501];
int search(int x,int y,int jia,int yi)
{
int yj=jia;
int yy=yi;
if(abs(jia-yi)<=m||jia==0||yi==0) return 1;
else
{
int j=x;
for(int i=y;i>=1;i--)
{
if(j>=1)
{
jia-=samea[i];
yi-=sameb[j];
if(abs(jia-yi)<=m||jia==0||yi==0)
{
ans+=search(x-j,y-i,yj-jia,yy-yi);
return ans;
}
j--;
}
}
return ans;
}
}
int main()
{
freopen("orz.in","r",stdin);
freopen("orz.out","w",stdout);
memset(samea,0,sizeof(samea));
memset(sameb,0,sizeof(sameb));
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>peo[i];
ans=1;
head1=1;
head2=1;
for(int i=1;i<n;i++)
{
if(peo[i]==1)
{
if(peo[i]==peo[1+i])
samea[head1]++,jia++;
else
{
samea[head1]++;
jia++;
head1++;
}
}
else
{
if(peo[i]==peo[i+1])
sameb[head2]++,yi++;
else
{
sameb[head2]++;
yi++;
head2++;
}
}
}
if(peo[n]==1) jia++;
else yi++;
int yj=jia,yy=yi;
cout<<min(head1+head2-2,search(head2,head1,jia,yi))<<endl;
return 0;
}
試後參照ly的想法自己寫了一遍,然後發現有三個WA:
代碼:
#include<bits/stdc++.h>
using namespace std;
int n,m,ans=0;
int peo[2600];
int jia=0,yi=0;
void classroom(int jia,int yi,int wrx,int hfz)
{
if(abs(jia-yi)<=m||jia==0||yi==0) ans++;
else
{
int wmx=jia,wxy=yi;
for(int i=wrx;i>=hfz;i--)
{
if(peo[i]==1) jia--;
else yi--;
if(abs(jia-yi)<=m||jia==0||yi==0)
{
ans++;
classroom(wmx-jia,wxy-yi,wrx,i+1);
break;
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>peo[i];
if(peo[i]==1) jia++;
else yi++;
}
classroom(jia,yi,n,1);
cout<<ans<<endl;
return 0;
}
這也說明了通過簡單的逆向推理是有缺陷的。所以DP終究還是有DP的道理,處理問題的時候不能只追求些程式碼一時的輕鬆,問題一定是要考慮全面的,不能僅僅通過自己簡簡單單的猜想而且不加驗證就開始程式設計。算灋雖然在思考時燒腦,但解决問題一定要抱著考慮問題全面的心態。