HFOI2017.7.13校内赛(普及组)题解

来源:互联网 发布:知乎wifi不能用 编辑:程序博客网 时间:2024/06/01 22:53
T1:分解因数
描述
    给出一个正整数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。

递归求解。

代码:

#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));}}
T2:单词序列
描述
    给出两个单词(开始单词和结束单词)以及一个词典。找出从开始单词转换到结束单词,所需要的最短转换序列。转换的规则如下:
    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类型单个字节的最大值,方便memsetint 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;}