HFOI2017.7.13校內賽(普及組)題解
描述
給出一個正整數a,要求分解成若干個正整數的乘積,即a = a1 * a2 * a3 * ... * an,並且1 < a1 <= a2 <= a3 <= ... <= an,問這樣的分解的種數有多少。注意到a = a也是一種分解。
輸入
第1行是測試資料的組數n,後面跟著n行輸入。每組測試資料佔1行,包括一個正整數a (1 < a < 32768)
輸出
n行,每行輸出對應一個輸入。輸出應是一個正整數,指明滿足要求的分解的種數
樣例輸入
2
2
20
樣例輸出
1
4
定義f(k,b)函式,表示待分解的數字為k,目前最大的非1因數為i。
遞迴求解。
程式碼:
T2:單詞序列#include<cstdio> int f(int k,int b) { int ans=0,i; if(k==1)return 1; for(i=b;i<=k;i++) { if(k%i==0) { k/=i; ans+=f(k,i); k*=i; } } return ans; } int main() { int n,i,k; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&k); if(k==1)printf("1\n"); else printf("%d\n",f(k,2)); } }
描述
給出兩個單詞(開始單詞和結束單詞)以及一個詞典。找出從開始單詞轉換到結束單詞,所需要的最短轉換序列。轉換的規則如下:
1、每次只能改變一個字母
2、轉換過程中出現的單詞(除開始單詞和結束單詞)必須存在於詞典中
例如:
開始單詞為:hit
結束單詞為:cog
詞典為:[hot,dot,dog,lot,log,mot]
那麼一種可能的最短變換是: hit -> hot -> dot -> dog -> cog,
所以返回的結果是序列的長度5;
注意:
1、如果不能找到這種變換,則輸出0;
2、詞典中所有單詞長度一樣;
3、所有的單詞都由小寫字母構成;
4、開始單詞和結束單詞可以不在詞典中。
輸入
共兩行,第一行為開始單詞和結束單詞(兩個單詞不同),以空格分開。第二行為若干的單詞(各不相同),以空格分隔開來,表示詞典。單詞長度不超過5,單詞個數不超過30。
輸出
輸出轉換序列的長度。
樣例輸入
hit cog
hot dot dog lot log
樣例輸出
5
正解是bfs暴搜(誒都是正解了還是什麼暴搜)。。。
考完試補了一個正解程式碼:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=31;
struct Node{int d;string s;Node(int d,string s):d(d),s(s){}};
int vis[31];
string ss[maxn],s,t;
int main()
{
cin>>s>>t;
int n=1,l=s.length();
while(cin>>ss[n]) n++;n--;
queue<Node>q;
q.push(Node(0,s));
while(!q.empty())
{
Node x=q.front();q.pop();
for(int i=0;i<l;i++)
{
for(char ch='a';ch<='z';ch++)
if(ch!=x.s[i])
{
char tmp=x.s[i];
x.s[i]=ch;
if(x.s==t)
{
printf("%d\n",x.d+2);
return 0;
}
for(int j=1;j<=n;j++)
if(x.s==ss[j])
{
if(!vis[j])
q.push(Node(x.d+1,x.s));
vis[j]=1;
}
x.s[i]=tmp;
}
}
}
printf("0\n");
return 0;
}
然而考試時不知道為什麼腦子短路寫了一個floyd,竟然過了,3ms。。。
【程式碼不堪入目】
#include<cstdio>
inline void f(int&m,int u){u<m&&(m=u);}
const int inf=1e6;
inline int h(char*s,char*t)
{
int ret=0;
while(*s)ret+=*(s++)!=*(t++);
return ret>1?inf:ret;
}
char s[35][9];
int dis[35][35];
int main()
{
int n;
for(n=0;~scanf("%s",s[n]);n++);
for(int i=0;i<n;i++)for(int j=0;j<n;j++)dis[i][j]=h(s[i],s[j]);
for(int k=0;k<n;k++)for(int i=0;i<n;i++)for(int j=0;j<n;j++)f(dis[i][j],dis[i][k]+dis[k][j]);
printf("%d\n",dis[0][1]==inf?0:dis[0][1]+1);
return 0;
}
好吧就是定義h函式為從字串s到字串t的長度,然後直接floyd暴算。。。
20行程式碼強行AC
T3:一個人的旅行
Problem Description
雖然草兒是個路痴(就是在杭電待了一年多,居然還會在校園裡迷路的人,汗~),但是草兒仍然很喜歡旅行,因為在旅途中 會遇見很多人(白馬王子,^0^),很多事,還能豐富自己的閱歷,還可以看美麗的風景……草兒想去很多地方,她想要去東京鐵塔看夜景,去威尼斯看電影,去陽明山上看海芋,去紐約純粹看雪景,去巴黎喝咖啡寫信,去北京探望孟姜女……眼看寒假就快到了,這麼一大段時間,可不能浪費啊,一定要給自己好好的放個假,可是也不能荒廢了訓練啊,所以草兒決定在要在最短的時間去一個自己想去的地方!因為草兒的家在一個小鎮上,沒有火車經過,所以她只能去鄰近的城市坐火車(好可憐啊~)。
Input
輸入資料有多組,每組的第一行是三個整數T,S和D,表示有T條路,和草兒家相鄰的城市的有S個,草兒想去的地方有D個;
接著有T行,每行有三個整數a,b,time,表示a,b城市之間的車程是time小時;(1=<(a,b)<=1000;a,b 之間可能有多條路)
接著的第T+1行有S個數,表示和草兒家相連的城市;
接著的第T+2行有D個數,表示草兒想去地方。
Output
輸出草兒能去某個喜歡的城市的最短時間。
Sample Input
6 2 3
1 3 5
1 4 7
2 8 12
3 8 4
4 9 12
9 10 2
1 2
8 9 10
Sample Output
9
典型的最短路問題(無向圖),floyd過不了【廢話】,dijkstra演算法78ms(我的),膜拜31ms大神lyb和zjc。
程式碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1005,n=1001,INT=0x3f3f3f;//INT是int型別單個位元組的最大值,方便memset
int mp[maxn][maxn],st[maxn],en[maxn],distanse[maxn];//mp是地圖,st是臨近城市,en是目標城市,distanse儲存起始點到每一個點的距離
bool found[maxn];//判重函式
int t,s,d,a,b,w,tmp;
inline void input()//輸入函式
{
int tot=t;
while(tot--)
{
scanf("%d%d%d",&a,&b,&w);
if(w<mp[a][b])mp[a][b]=mp[b][a]=w;
}
for(int i=0;i<s;i++)scanf("%d",&st[i]);
for(int i=0;i<d;i++)scanf("%d",&en[i]);
}
inline int choose()//選擇一條權值最短的邊(通向新節點)
{
int minn=INT;
int cnt=-1;
for(int i=1;i<1001;i++)
{
if(!found[i]&&distanse[i]<minn)
{
minn=distanse[i];
cnt=i;
}
}
return cnt;
}
void dijkstra(int v)//dijkstra演算法主過程
{
for(int i=0;i<maxn;i++)
{
distanse[i]=mp[v][i];
found[i]=0;
}
found[v]=1;
for(int i=0;i<n;i++)
{
int p=choose();
if(p==-1)return;
found[p]=1;
for(int j=0;j<n;j++)if(!found[j])if(distanse[p]+mp[p][j]<distanse[j])
distanse[j]=distanse[p]+mp[p][j];//鬆弛操作
}
}
int main()
{
while(scanf("%d%d%d",&t,&s,&d)!=EOF)//處理多組資料
{
tmp=INT;
memset(mp,INT,sizeof mp);//初始化
input();
for(int i=0;i<s;i++)
{
dijkstra(st[i]);
for(int j=0;j<d;j++)tmp=min(tmp,distanse[en[j]]);
}
printf("%d\n",tmp);
}
return 0;
}