目錄:
T1:笨小猴
T2:數列
T3:Jam的計數法
T4:傳紙條
這次的題一些洛谷上有 一些沒有 總之不是USACO的題了……
正題:
T1:笨小猴
題目描述
笨小猴的詞彙量很小,所以每次做英語選擇題的時候都很頭疼。但是他找到了一種方法,經試驗證明,用這種方法去選擇選項的時候選對的機率非常大!
這種方法的具體描述如下:假設maxn是單詞中出現次數最多的字母的出現次數,minn是單詞中出現次數最少的字母的出現次數,如果maxn-minn是一個質數,那麼笨小猴就認爲這是個Lucky Word,這樣的單詞很可能就是正確的答案。
輸入
輸入文件word.in只有一行,是一個單詞,其中只可能出現小寫字母,並且長度小於100。
輸出
輸出文件word.out共兩行,第一行是一個字符串,假設輸入的的單詞是Lucky Word,那麼輸出“Lucky Word”,否則輸出“No Answer”;
第二行是一個整數,如果輸入單詞是Lucky Word,輸出maxn-minn的值,否則輸出0。
樣例輸入
【輸入樣例1】
error
【輸入樣例2】
olympic
樣例輸出
【輸出樣例1】
Lucky Word
2
【輸出樣例1解釋】
單詞error中出現最多的字母r出現了3次,出現次數最少的字母出現了1次,3-1=2,2是質數。
【輸出樣例2】
No Answer
0
【輸出樣例2解釋】
單詞olympic中出現最多的字母出現了1次,出現次數最少的字母出現了1次,1-1=0,0不是質數。
分析:
此題可用一點小打表
打表找出100以內的質數 再分別找出
出現次數最多的字母
出現次數最少的字母
將他們相減 得到一個差
最後拿去匹配 輸出
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[27];
int main(){
freopen("word.in","r",stdin);
freopen("word.out","w",stdout);
int len=0,x=0,maxn=-9999,minn=9999;
string s;
cin>>s;
len=s.size();
for(int i=0;i<=len-1;i++){
x=s[i];
a[x-97]++; //記錄每個字母出現次數
}
const int prime[25]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
//100以內的質數表
for(int i=0;i<26;i++){
if(a[i]<minn&&a[i]!=0)minn=a[i]; //最少
}
for(int i=0;i<26;i++){
if(a[i]>maxn)maxn=a[i]; //最大
}
int sub=maxn-minn; //差
for(int i=0;i<=24;i++){
if(sub==prime[i]){ //匹配了
cout<<"Lucky Word"<<endl;
cout<<sub;
return 0;
}
}
cout<<"No Answer"<<endl<<"0";
return 0;
}
T2:數列
題目描述
給定一個正整數k(3≤k≤15),把所有k的方冪及所有有限個互不相等的k的方冪之和構成一個遞增的序列,例如,當k=3時,這個序列是:
1,3,4,9,10,12,13,…
(該序列實際上就是:30,31,30+31,32,30+32,31+32,30+31+32,…)
請你求出這個序列的第N項的值(用10進制數表示)。
例如,對於k=3,N=100,正確答案應該是981。
輸入
輸入文件sequence.in 只有1行,爲2個正整數,用一個空格隔開:
k N(k、N的含義與上述的問題描述一致,且3≤k≤15,10≤N≤1000)。
輸出
輸出文件sequence.out 爲計算結果,是一個正整數(在所有的測試數據中,結果均不超過2.1*10^9)。(整數前不要有空格和其他符號)。
樣例輸入
3 100
樣例輸出
981
分析:
這道題可進制轉換
也可以做搜索 DFS
看註釋去
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long a,k,x[501],y[1101],poww=1,can=0;
void dfs(long long poww,long long l)
{
if(poww==11)
{
return;
}
else{
int cat=0;
for(int i=1;i<=can;i++)
{
if(l==y[i]) //判斷重複值
{
cat++;
break;
}
}
if(cat==0) //莫得加入數組
{
can++;
y[can]=l;
}
dfs(poww+1,l+x[poww]);
dfs(poww+1,l); //加或不加
}
}
int main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
cin>>a>>k;
x[0]=1;
for(int i=1;i<=10;i++)
{
x[i]=poww*a;
poww=a*poww;
}//用x數組表示a的poww次方數;
//因爲題目中的範圍小於等於1000;
//故到10就行了;
dfs(0,0);
sort(y+1,y+can+1);
cout<<y[k+1]; //數組第一個值爲0
return 0;
}
T3:Jam的計數法
題目描述
Jam是個喜歡標新立異的科學怪人。他不使用阿拉伯數字計數,而是使用小寫英文字母計數,他覺得這樣做,會使世界更加豐富多彩。在他的計數法中,每個數字的位數都是相同的(使用相同個數的字母),英文字母按原先的順序,排在前面的字母小於排在它後面的字母。我們把這樣的“數字”稱爲Jam數字。
在Jam數字中,每個字母互不相同,而且從左到右是嚴格遞增的。每次,Jam還指定使用字母的範圍,例如,從2到10,表示只能使用{b,c,d,e,f,g,h,i,j}這些字母。如果再規定位數爲5,那麼,緊接在Jam數字“bdfij”之後的數字應該是“bdghi”。(如果我們用U、V依次表示Jam數字“bdfij”與“bdghi”,則U<V,且不存在Jam數字P,使U<P<V)。你的任務是:對於從文件讀入的一個Jam數字,按順序輸出緊接在後面的5個Jam數字,如果後面沒有那麼多Jam數字,那麼有幾個就輸出幾個。
輸入
輸入文件count.in 有2行:
第1行爲3個正整數,用一個空格隔開:s t w(其中s爲所使用的最小的字母的序號,t爲所使用的最大的字母的序號。w爲數字的位數,這3個數滿足:1≤s≤26, 2≤w≤t-s )
第2行爲具有w個小寫字母的字符串,爲一個符合要求的Jam數字。 所給的數據都是正確的,不必驗證。
輸出
輸出文件count.out 最多爲5行,爲緊接在輸入的Jam數字後面的5個Jam數字,如果後面沒有那麼多Jam數字,那麼有幾個就輸出幾個。每行只輸出一個Jam數字,是由w個小寫字母組成的字符串,不要有多餘的空格。
樣例輸入
2 10 5
bdfij
樣例輸出
bdghi
bdghj
bdgij
bdhij
befgh
分析:
dfs 需要注意如何退出
後面就是普通dfs
退出部分則是:
不斷地匹配 標記 停止循環 等等等等……
詳見註釋
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,flag,ans,s,t;
char a[17],an[17];
char b[27]={'*','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; //字符表
int vis[27];
void dfs(int cur){ //dfs
if(cur==n+1){
int f2=0,f=0;
for(int i=1;i<=n;i++) if(a[i]!=an[i]) f=1; //不相同先標記
if(f==0) return;
for(int i=1;i<=n;i++){
if(an[i]>a[i]){
break; //判斷大小
}
else if(an[i]<a[i]){ //下一種情況 標記
f2=1;
break;
}
}
if(f2==1) return;
flag++; //做完一位上的字符
for(int i=1;i<n;i++) cout<<an[i]; //輸出即可
cout<<an[n]<<endl;
if(flag==5) exit(0); //共5位
}else{
for(int i=s;i<=t;i++){
if(vis[i]==0&&b[i]>an[cur-1]){ //深搜 下一個數
an[cur]=b[i];
vis[i]=1;
dfs(cur+1);
vis[i]=0;
}
}
}
}
int main() {
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d%d%d",&s,&t,&n);
for(int i=1;i<=n;i++) cin>>a[i]; //讀入
dfs(1);
return 0;
}
T4:傳紙條
題目描述
小淵和小軒是好朋友也是同班同學,他們在一起總有談不完的話題。一次素質拓展活動中,班上同學安排做成一個m行n列的矩陣,而小淵和小軒被安排在矩陣對角線的兩端,因此,他們就無法直接交談了。幸運的是,他們可以通過傳紙條來進行交流。紙條要經由許多同學傳到對方手裏,小淵坐在矩陣的左上角,座標(1,1),小軒坐在矩陣的右下角,座標(m,n)。從小淵傳到小軒的紙條只可以向下或者向右傳遞,從小軒傳給小淵的紙條只可以向上或者向左傳遞。
在活動進行中,小淵希望給小軒傳遞一張紙條,同時希望小軒給他回覆。班裏每個同學都可以幫他們傳遞,但只會幫他們一次,也就是說如果此人在小淵遞給小軒紙條的時候幫忙,那麼在小軒遞給小淵的時候就不會再幫忙。反之亦然。
還有一件事情需要注意,全班每個同學願意幫忙的好感度有高有低(注意:小淵和小軒的好心程度沒有定義,輸入時用0表示),可以用一個0-100的自然數來表示,數越大表示越好心。小淵和小軒希望儘可能找好心程度高的同學來幫忙傳紙條,即找到來回兩條傳遞路徑,使得這兩條路徑上同學的好心程度只和最大。現在,請你幫助小淵和小軒找到這樣的兩條路徑。
輸入
輸入文件message.in的第一行有2個用空格隔開的整數m和n,表示班裏有m行n列(1<=m,n<=50)。
接下來的是一個m*n的矩陣,矩陣中第i行j列的整數表示坐在第i行j列的學生的好心程度。每行的n個整數之間用空格隔開。
輸出
輸出文件message.out共一行,包含一個整數,表示來回兩條路上參與傳遞紙條的學生的好心程度之和的最大值。
樣例輸入
3 3
0 3 9
2 8 5
5 7 0
樣例輸出
34
分析:
DP DP DP
本來想着用搜索淼過 結果被制裁
一邊傳紙條一邊判斷上下左右的大小
找到最大的就往那裏累加
然後繼續走 直到中點爲止
啊啊啊 三維數組的DP我人都傻了
CODE:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int f[101][101][101];
int a[101][101];
int m,n,cnt;
int main()
{
freopen("message.in","r",stdin);
freopen("message.out","w",stdout);
cin>>m>>n;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
memset(f,-1,sizeof(f));
f[2][1][1]=0; //初始化起點
for(int k=3;k<m+n;k++) //枚舉路徑
for(int i=1;i<n;i++) //枚舉斜線
for(int j=i+1;j<=n;j++)
{
cnt=f[k][i][j];
cnt=max(f[k-1][i][j],cnt); //上下左右
cnt=max(f[k-1][i-1][j],cnt);
cnt=max(f[k-1][i][j-1],cnt);
cnt=max(f[k-1][i-1][j-1],cnt);
if(cnt==-1) continue;
f[k][i][j]=cnt+a[k-i][i]+a[k-j][j]; //加進去
}
cout<<f[m+n-1][n-1][n];
return 0;
}