2013 福州大学第十届程序设计竞赛

A题:中学物理题,直接求就好了;

#include<stdio.h>
#include<string.h>
int main()
{
    __int64 cas,s,h,vx,vy;
    scanf("%I64d",&cas);
    while(cas--)
    {
        scanf("%I64d%I64d%I64d%I64d",&s,&h,&vx,&vy);
        vx=s/vx;
        vy=vy*vx-5*vx*vx;
        if(vy>=h) puts("good done!");
        else puts("poor Merida!");
    }
    return 0;
}

B题:kmp算法;

#include<stdio.h>
#include<string.h>
char substr[110];
int next[110];
char tolower(char ch)
{
    if(ch>='A'&&ch<='Z') return ch-'A'+'a';
    return ch;
}
void get(int m)
{
    int i=-1,j=0;next[0]=-1;
    while(j<m){
        if(i==-1||tolower(substr[i])==tolower(substr[j]))
        {
            i++;j++;
            next[j]=i;
        }else i=next[i];
    }
}
char str[55000];
int kmp(int s,int m,int n)
{
    int i=s,j=0;
    while(i<n&&j<m){
        if(j==-1||tolower(str[i])==tolower(substr[j])){
            i++;j++;
        }else j=next[j];
    }
    return j<m?-1:i-m;
}
char des[110];
int main()
{
    int i,n,m,k,g;
    while(scanf("%s",substr)!=EOF)
    {
        m=strlen(substr);get(m);
        getchar();
        gets(des);g=strlen(des);
        gets(str);n=strlen(str);
        for(i=0;i<n;){
            k=kmp(i,m,n);
            if(k==-1){
                printf("%s",str+i);
                i=n;
            }else {
                for(;i<k;i++) putchar(str[i]);
                i=k+m;
                for(k=0;k<g;k++) putchar(des[k]);
            }
        }
        putchar('\n');
    }
    return 0;
}

C题:直接统计

#include<stdio.h>
#include<string.h>
int a[]={1,0,0,0,1,0,1,0,2,1};
int main()
{
    int cas,n,sum;
    scanf("%d",&cas);
    while(cas--)
    {
        sum=0;
        scanf("%d",&n);
        while(n) sum+=a[n%10],n/=10;
        printf("%d\n",sum);
    }
    return 0;
}

D题:搜索

/*
 * 题目:吃豆人
 * 题目链接:http://acm.fzu.edu.cn/contest/problem.php?cid=129&sortid=4
 * 题目描述:
 * 地图上有n×m个格子,每格地形可能为空地或者障碍物,吃豆人可以在空地上移动,
 *  吃豆人每移动一格需要1s时间,并且只能朝上下左右四个方向移动,特别的是吃豆人还能吐出舌头,
 *  舌头每移动一格需要0.1s时间,舌头只可以走直线。不必考虑吃豆人转身所需要的时间。
 *  游戏中还有加速道具,一旦得到加速道具,吃豆人就获得2倍移动速度,吐舌头的速度没有增加,
 *  即走1格用0.5s。现在地图上有且只有一颗豆子。游戏中有.代表空地;X表示障碍,吃豆人不能越过障碍;
 *  B代表豆子;S代表加速道具,并且地图上道具总数不超过1个,道具所在的位置为空地,得到道具后立即使用,
 *  道具立即消失,地形变为空地,不能用舌头去取道具;P表示吃豆人,吐舌头的时候吃豆人不能移动。
 *  求最快用多少s吃到豆子,结果保留1位小数?
 * 
 * 解题思路:
 * 和往常用bfs去搜索一条最优的路径的做法一样,这个也可以采用bfs搜索,因为数据范围很小用dfs也可以;
 *  我是用bfs做的,用dp[i][j][s]表示从起点走到(i,j)点且当前速度为s的最短时间,这样不断的去更新所有
 *  点,在每一点上都尝试是否可以吃到豆子,如果可以吃到豆子,则去尝试更新吃豆子的最短时间,这样直到队列为空。
 *  
 *  最后如果可以吃到豆子,输出能吃到豆子的最短时间,否则输出-1;
 *  代码如下:
 */

#include<stdio.h>
#include<string.h>
#include<queue>

using namespace std;

int op[4][2]={1,0,0,1,-1,0,0,-1};
char mat[30][30];
int n,m;
int dp[30][30][15],vis[30][30][15];
void update(int r,int c,int s,int &Min) //判断是否可以吃到豆子,并去更新最短时间
{
        int i;
        for(i=r+1;i<=n;i++)
            if(mat[i][c]!='.'&&mat[i][c]!='S')break;
        if(i<=n&&mat[i][c]=='B'&&dp[r][c][s]+(i-r)*2<Min)
            Min=dp[r][c][s]+(i-r)*2;
        for(i=r-1;i>0;i--)
            if(mat[i][c]!='.'&&mat[i][c]!='S')break;
        if(i>0&&mat[i][c]=='B'&&dp[r][c][s]+(r-i)*2<Min)
            Min=dp[r][c][s]+(r-i)*2;
        for(i=c+1;i<=m;i++)
            if(mat[r][i]!='.'&&mat[r][i]!='S') break;
        if(i<=m&&mat[r][i]=='B'&&dp[r][c][s]+(i-c)*2<Min)
            Min=dp[r][c][s]+(i-c)*2;
        for(i=c-1;i>0;i--)
            if(mat[r][i]!='.'&&mat[r][i]!='S') break;
        if(i>0&&mat[r][i]=='B'&&dp[r][c][s]+(c-i)*2<Min)
            Min=dp[r][c][s]+(c-i)*2;
}
int bfs(int r,int c) //搜索函数
{
    int i,j,x,y,Min=10000000,s,ts,k;
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;i++)
		for(j=1;j<=m;j++) 
			for(k=1;k<=10;k++) 
				dp[i][j][k]=100000000;
    queue<int> X,Y,S;
    vis[r][c][10]=1;dp[r][c][10]=0;
    X.push(r);Y.push(c);S.push(10);
    while(!X.empty()){
        r=X.front();X.pop();
        c=Y.front();Y.pop();
        s=S.front();S.pop();
        update(r,c,s,Min);
        for(i=0;i<4;i++) //往4个方向搜
        {
			ts=s;
            x=r+op[i][0];
            y=c+op[i][1];
            if(x<1||x>n||y<1||y>m||mat[x][y]=='X'||(mat[x][y]=='S'&&s==5)) continue;
            if(mat[x][y]=='S') ts=s/2;
            if(dp[r][c][s]+s<dp[x][y][ts]){
                 dp[x][y][ts]=dp[r][c][s]+s;
                 update(x,y,ts,Min);
                 if(!vis[x][y][ts]){
                    vis[x][y][ts]=1;
                    X.push(x);Y.push(y);S.push(ts);
                 }
            }
        }
        vis[r][c][s]=0;
    }
    if(Min==10000000) Min=-1;
    return Min;
}
int main()
{
    int i,j,sx,sy;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;i++)
            scanf("%s",mat[i]+1);
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                if(mat[i][j]=='P'){ sx=i;sy=j;}
        sy=bfs(sx,sy);
        if(sy<0) printf("-1\n");
        else printf("%.1lf\n",sy/10.0);
    }
    return 0;
}


 

E题:看懂题意的公式后,s(x,m)的范围不会超过1000,所以x的取值范围就在sqrt(n)至sqrt(n)-1000左右,

解释:因为s(x,m)的最大值不会超过1000,当x为(sqrt(n)-1000)以下时,x*(x+s(x,m))<sqrt(n)×sqrt(n)<n;所以就不可能了

枚举几百上千次就好了。

#include<stdio.h>
#include<math.h>
#include<string.h>

#define _LL __int64
#define FM "%I64d"
int m;
_LL F(_LL x)
{
    _LL t=x,sum=x*x;
    while(x){
        sum+=(x%m)*t;x/=m;
    }
    return sum;
}
int main()
{
    int cas;
    _LL n,i,l;
    scanf("%d",&cas);
    while(cas--){
        scanf(FM,&n);
        scanf("%d",&m);
        l=(_LL)sqrt((double)(n+1));i=l-1000;
        if(i<=0)i=1;
        for(;i<=l;i++)
            if(F(i)==n) break;
        if(i>l) i=-1;
        printf("%d\n",(int)i);
    }
    return 0;
}

F题:不会


G题:枚举第一条边的长度,统计当第一条边确定时,第二三条边可能的方案数;

三角形的二三条边中,令第二条边慢慢增大,第三条边慢慢减小,所以当第一边确定时的答案就是:
Min(第二条可以增大的最大值,第三条可以减小的最大值,第三条边的上限减去第二条边的下限除以2);



H题:用ac自动机求出母串每一个匹配点的向前的最短匹配距离,然后求出母串每一个点的向前的最大合法长度,取所有中的最大值就是答案;

这题貌似用后缀数组也可以解;

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;

#define N 101000

int ch[N][26],cnt,f[N],last[N],val[N],pos[N];
struct aho_corasick
{
    aho_corasick(){
        cnt=0;
        memset(ch,0,sizeof(ch));
        memset(val,0,sizeof(val));
        memset(pos,0,sizeof(pos));
    }
    int newnode(){ return ++cnt; }
    int idx(char c){ return c-'a'; }
    void insert(char *s,int n)
    {
        int root=0,i;
        for(i=0;i<n;i++)
        {
            int u=idx(s[i]);
            if(!ch[root][u])ch[root][u]=newnode();
            if(i==n-1) val[ch[root][u]]=n;
            root=ch[root][u];
        }
    }
    void getfail()
    {
            queue <int> q;
            f[0]=0;
            int i,u;
            for(i=0;i<26;i++)
            {
                u=ch[0][i];
                if(u){
                    f[u]=0; q.push(u);last[u]=0;
                }
            }
            while(!q.empty())
            {
                int r=q.front(); q.pop();
                for(i=0;i<26;i++)
                {
                    u=ch[r][i];
                    if(!u){ ch[r][i]=ch[f[r]][i]; continue; }
                    q.push(u);
                    int v=f[r];
                    while(v&&!ch[v][i]) v=f[v];
                    f[u]=ch[v][i];
                    last[u]=val[f[u]]?f[u]:last[f[u]];
                }
            }
    }
    int find(char *t,int n)
    {
        int i,j=0,temp;
        for(i=0;i<n;i++)
        {
            int c=idx(t[i]);
            //while(j&&!ch[j][c])j=f[j];
            j=ch[j][c];
            temp=j;
            while(temp)
            {
                if(val[temp]&&(!pos[i]||val[temp]<pos[i]))
                    pos[i]=val[temp];
                temp=last[temp];
            }
        }
        return 0;
    }
};
char str[1100000],substr[110];
int main()
{

    int i,n,len;
    while(scanf("%s",str)!=EOF)
    {
        len=strlen(str);
        scanf("%d",&n);
        aho_corasick ac;
        for(i=1;i<=n;i++)
        {
            scanf("%s",substr);
            ac.insert(substr,strlen(substr));
        }
        ac.getfail();
        ac.find(str,len);
        //for(i=0;i<len;i++)printf("%d",pos[i]);
        //printf("\n");
        if(!pos[0])pos[0]=2;
        for(i=1,n=0;i<len;i++)
        {
            if(!pos[i])
                pos[i]=pos[i-1]+1;
            else{
                if(pos[i]>i-n+pos[n])
                    pos[i]=i-n+pos[n];
                n=i;
            }
        }
        //for(i=0;i<len;i++)printf("%d",pos[i]);
        //printf("\n");
        for(n=i=0;i<len;i++)
            if(pos[i]>n) n=pos[i];
        printf("%d\n",n-1);
    }
    return 0;
}

I题:不会




评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值