Problem A:NEFU31 字符串合併
這題真水。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
string s1, s2;
int main()
{
ios::sync_with_stdio(false);
while(cin>>s1>>s2)
cout<<s1+s2<<endl;
return 0;
}
Problem B:NEFU194 迴文字符串
方法1:將字符串逆序後與原字符串比對。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
bool judge(string str)
{
string tmp=str;
reverse(str.begin(), str.begin()+str.size());
return tmp==str;
}
int main()
{
ios::sync_with_stdio(false);
string s;
int n;
while(cin>>n)
{
while(n--)
{
cin>>s;
if(judge(s)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}
方法2:兩個指針分別從首尾兩端一一比較。
#include<bits/stdc++.h>
using namespace std;
int n;
int main()
{
ios::sync_with_stdio(false);
while(~scanf("%d", &n))
{
while(n--)
{
char str[110];
scanf("%s", str+1);
int len=strlen(str+1);
bool flag = 1;
if(len%2)
{
for(int i=1,j=len; i<=len/2,j>=len/2+2; i++,j--)
if(str[i] != str[j])
{
flag = 0;
break;
}
}
else
{
for(int i=1,j=len; i<=len/2,j>=len/2+1; i++,j--)
if(str[i] != str[j])
{
flag = 0;
break;
}
}
if(flag) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
Problem C:NEFU549 氣球
這個題在之前的組隊賽中做過,當時採用的是結構體,這裏用string+map做一下。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
map<string, int> vis;
int main()
{
ios::sync_with_stdio(false);
int n;
while(cin>>n)
{
if(!n) return 0;
vis.clear();
for(int i=1; i<=n; i++)
{
string str;
cin>>str;
vis[str]++;
}
string ans;
int maxn = 0;
for(map<string, int>::iterator it=vis.begin(); it!=vis.end(); it++)
{
string tmp = it->first;
if(maxn<vis[tmp])
{
maxn = vis[tmp];
ans = tmp;
}
}
cout<<ans<<endl;
}
}
Problem D:NEFU1001 取子字符串
方法1:比較原始的方法,從n輸出到m。
#include<bits/stdc++.h>
using namespace std;
string str;
int n, m;
int main()
{
ios::sync_with_stdio(false);
while(cin>>str)
{
cin>>n>>m;
for(int i=n-1; i<=m-1; i++)
cout<<str[i];
cout<<endl;
}
return 0;
}
方法2:使用string自帶的substr直接返回對應位置。
#include<bits/stdc++.h>
using namespace std;
string str;
int n, m;
int main()
{
ios::sync_with_stdio(false);
while(cin>>str)
{
cin>>n>>m;
cout<<str.substr(n-1, m-n+1)<<endl;
}
return 0;
}
Problem E:NEFU1019 strange string
純模擬,菜雞蒟蒻專用做法。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int a[26];
int main()
{
ios::sync_with_stdio(false);
string str;
while(cin>>str)
{
bool flag = 0;
fill(a, a+26, 0);
if(str.size()==3)
{
if(str[0]!=str[1] && str[1]!=str[2] && str[0]!=str[2])
flag = 1;
}
else if(str.size()==6)
{
if(str[0]==str[1] && str[2]==str[3] && str[4]==str[5])
if(str[1]!=str[2] && str[3]!=str[4] && str[1]!=str[4])
flag = 1;
}
else if(str.size()==9)
{
if((str[0]==str[1]&&str[1]==str[2])&&(str[3]==str[4]&&str[4]==str[5])&&(str[6]==str[7]&&str[7]==str[8]))
if(str[0]!=str[3] && str[3]!=str[6] && str[0]!=str[6])
flag = 1;
}
else flag = 0;
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
Problem F:NEFU2132 字符串處理
樣例解釋:aba
的迴文子串爲a
, b
, a
, aba
。
思路:先篩選首尾相同字母的字符串,如aa,bcb。然後對篩選出來的字符串判斷,依次比較前後對應兩個字符是否相同,相同則繼續判斷,不相同則結束當前字符串的判斷。比較到最後會有兩種情況:
- 只剩一個字符,計數器+1;
- 只剩兩個字符,若相等。計數器+1。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int cnt = 0;
void find(int n, int m, string str)
{
if(n-m==1 || n==m) cnt++;
else
{
if(str[m]==str[n])
find(n+1, m-1, str);
else return;
}
}
int main()
{
ios::sync_with_stdio(false);
string s;
while(cin>>s)
{
cnt = 0;
for(int i=0; i<s.size(); i++)
for(int j=i+1; j<s.size(); j++)
if(s[i]==s[j])
find(i, j, s);
cout<<cnt+s.size()<<endl;
}
return 0;
}
Problem G:NEFU2131 字符串乘方
類似於KMP算法中next數組的求解。直接從字符串匹配那篇博客裏套用了,就不多做解釋了。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int Next[1000010];
void getNEXT(string str)
{
Next[0] = -1;
int i=-1, j=0;
while(j < str.size())
{
if(i==-1 || str[j]==str[i])
{
i++;
j++;
Next[j] = i;
if(str[j] != str[i]) Next[j] = i;
else Next[j] = Next[i];
}
else i = Next[i];
}
}
int main()
{
ios::sync_with_stdio(false);
string s;
while(cin>>s)
{
if(s[0] == '.') return 0;
getNEXT(s);
int len = s.size();
if(len%(len-Next[len])==0)
cout<<len/(len-Next[len])<<endl;
else cout<<1<<endl;
}
}
Problem H:NEFU2130 字符串匹配
說實話一看到這題激動壞了,什麼BF、RK、KMP、Sunday算法啥的我都寫過博客了,可以直接拿來用了吧?
但是一看題,,好像不是這麼一回事。。。
其實這題AC率慘不忍睹是樣例的鍋。NEFU1683的樣例就好多了。
首先看一下對匹配程度的定義,定義中包括兩個名詞:對齊,匹配程度。
- 對齊:將某一字符串的首字符與另一字符串的某一字符對齊,然後後面的字符也一一對齊,直至某一字符串的串尾爲止。
注意:“某一字符串”暗示着兩個字符串都要做一次對齊。 - 匹配程度:對於每一組對齊的兩個字符,若這兩個字符相等,則計數。匹配程度爲每種對齊方法的計數的最大值。
設有輸入數據:abdf
、bdefgh
:答案應爲appx(abdf,bdefgh) = 2/5
。
假定我們將其中的一個字符串叫做主串,另一個則稱爲模式串。那麼我們首先固定主串,讓模式串來與主串匹配,同時使用一個cnt計數器和最大值maxn來記錄。
按照大多數人的思路,我們先將長度小abdf的串定爲模式串,長度大bdefgh的定爲主串。
初始cnt和maxn值爲0。
第一輪,首位對齊:
cnt=1,maxn=1;
第二輪,模式串後移:
cnt=0,maxn=1;
第三輪,模式串繼續後移:
cnt=0,maxn=1;
第n輪,模式串首後移至主串尾,本輪結束後匹配結束:
cnt=0,maxn=1。
很多人的處理到這裏就結束了,然後就WA了。其實題中“某一字符串”已經暗示兩個字符串都分別要做一次主串和一次模式串。接下來主串和模式串交換。
第一輪,首位對齊:cnt=1,maxn=1;
第二輪,模式串後移:
cnt=2,maxn=2;
第三輪,模式串繼續後移:
cnt=0,maxn=2;
第四輪,模式串繼續後移:
cnt=0,maxn=2。
所以匹配程度應該是2,而不是1。
這組數據也很好的解釋了爲什麼兩個字符串都分別要進行匹配。
接下來就是處理細枝末節了:求一下兩串總長,用最大公約數來約分等等。
注意,以下兩種情況需要特判:
- [ 1 ] maxn爲0(即沒有匹配)時應單獨輸出0;
- [ 2 ] 匹配程度的二倍和兩串總長度相等時應單獨輸出1。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int comp(string str1, string str2) // str1固定,str2移動
{
int len1=str1.size(), len2=str2.size();
int maxn = -1;
for(int i=0; i<len1; i++) // 定位str2首位
{
int cnt=0;
for(int j=0; j<len2; j++) // 逐位比較
{
if(str1[i+j] == str2[j]) cnt++;
if(i+j >= len1) break; // 直至某一字符串的串尾爲止
}
maxn = max(maxn, cnt);
}
return maxn;
}
int main()
{
ios::sync_with_stdio(false);
string s1, s2;
while(cin>>s1 && s1[0]!='-')
{
cin>>s2;
int num1 = 2*max(comp(s1, s2), comp(s2, s1)); // 取二者最大值
int num2 = s1.size()+s2.size();
int ans = __gcd(num1, num2);
int ans1=num1/ans, ans2=num2/ans;
/* 因爲樣例問題這裏就錯了
if(num1==0)
cout<<"appx("<<s1<<","<<s2<<") = 0"<<endl;
else if(num1==num2)
cout<<"appx("<<s1<<","<<s2<<") = 1"<<endl;
else cout<<"appx("<<s1<<","<<s2<<") = "<<ans1<<"/"<<ans2<<endl;
*/
if(num1==0)
cout<<"appx("<<s1<<","<<s2<<") = 0"<<endl;
else if(num1==num2)
cout<<"appx("<<s1<<","<<s2<<") = 1"<<endl;
else cout<<"appx("<<s1<<","<<s2<<") = "<<ans1<<"/"<<ans2<<endl;
}
return 0;
}