合工大 程序设计方法与艺术 解题报告

题目全部来自于往年省赛

题目A. 机器人足球

足球场地长为 100,宽为 20,对方的球门坐标为(100,10),你要控制一个机器人 踢球,初始位置为(x,y)。机器人可以朝任何方向移动,但不能超出场地边界。当 机器人与球门距离不超过 10 时,可以射门。问机器人从初始位置出发到射门, 最少要移动多少距离?(四舍五入到小数点后 3 位)

解题思路:
根据输入的坐标,判断该坐标和球门的距离,在根据距离和10比较,判断此时能否射门,如果不能射门,输出需要移动的距离。

具体解法:
计算平面上两点之间的距离,判断是否大于10,如果小于10,则直接输出0.000,如果大于10,则用距离减去10,输出差,是最少移动距离。

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

int main(void)
{
    int x,y;
    float way;
    scanf("%d %d",&x,&y);

    x = 100-x;
    y = y-10;
    way = sqrt(x*x+y*y);
    if (way<=10)
    {
        printf("0.000");
    }
    else
    {
        printf("%.3f",way-10);
    }
    return 0;
}

题目B.纸牌识别

Alice 沉迷于机器人研究,他打算做一个机器人来检查一副扑克是否完整。现在, 他想请你帮他写一个程序,来识别纸牌。每张纸牌都有一个花色(四种花色,分 别用大写字母 P,K,H,T 表示)和一个数字点数(1-13)。纸牌可以用 ABC 的形式来表示,A 代表花色,BC 代表数字,如果数字小于 10,会有一位补 0。 比如花色是 P,数字是 9 的纸牌会表示成 P09。一副完整的纸牌有 52 张牌,四 种不同的花色各有 1 张数字 1-13 的牌。 你的程序要读入一个字符串,表示缺少的纸牌有哪些。如果包含相同的纸牌(花 色数字都相同)输出 GRESKA,否则输出每种花色剩余的纸牌数量。

解题思路:
创建一个字符数组用于储存输入的字符串,建立一个二维数组用于储存输入的纸牌数据,记录相应纸牌的出现次数。如果有纸牌出现两次或两次以上,则直接输出“GRESKA”。如果输入的纸牌不包含相同的,则统计每种花色剩余纸牌的数目,并输出。

具体解法:
输入符合要求的字符串,判断每张纸牌的出现次数,再统计输入纸牌的数量,如果在统计过程中,发现某张纸牌的出现次数大于或等于2,则直接输出“GRESKA”,并结束运行,如果没有出现该情况,则完成统计,通过循环输出每一种花色剩余纸牌的数量。

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

int main(void)
{
    char s[1000];
    int j[5][14];
    int num[5];
    int i,k,leng;
    int sum;

    scanf("%s",s);
    leng = strlen(s);

    for(i=1;i<5;i++)
    {
        for(k=1;k<14;k++)
        {
            j[i][k] = 0;
        }
        num[i] = 0;
    }

    for(i=1;i<leng;i=i+3)
    {
        sum = (s[i]-'0')*10+(s[i+1]-'0');
        if(s[i-1]=='P')
        {
            j[1][sum]++;
        }
        else if(s[i-1]=='K')
        {
            j[2][sum]++;
        }
        else if(s[i-1]=='H')
        {
            j[3][sum]++;
        }
        else
        {
            j[4][sum]++;
        }
    }

    for(i=1;i<5;i++)
    {
        for(k=1;k<14;k++)
        {
            if(j[i][k]==1)
            {
                num[i]++;
            }
            else if(j[i][k]>1)
            {
                printf("GRESKA");
                return 0;
            }
        }
    }

    for(i=1;i<5;i++)
    {
        printf("%d ",13-num[i]);
    }
    return 0;
}

题目J.密信

Alice 想给 Bob 发短信,短信的内容可以看成是一个只有小写字母的字符串 p; 为了加密短信,Alice 需要只有小写字母长度为 n 的字符串 h,并且 p 是 h 的子 串;Alice 想知道,这样的字符串有多少种。 给出 n 和 M 还有字符串 p,假设一共有 K 种不同的 h,输出 K mod M

解题思路:
运用动态规划和矩阵优化,统计出字符串的数量,再用总数除以输入的M,得出最终的结果。

具体解法:
先输入执行的次数,然后输入字符串的长度,和后面需要除以的M,再得出需要加密的字符串的长度。运用定义的函数gf和结构体,最终算出最终的结果。

#include<stdio.h>
#include<string.h>
typedef long long ll;
typedef unsigned long long ull;

int f[50],len;
int t;
long long n,m;
char s[50];
void gf()
{
    int j = 0;
    for(int i=1;i<=len-1;i++){
        while (j&&s[j]!=s[i])
        {
            j=f[j];

        }
        if (s[j]==s[i])
        {
            ++j;
        }
        f[i+1] = j;
    }
}

ull qmul(const ull a, const ull b, const ull md) {
	ll c=(ll)a*b-(ll)((ull)((long double)a*b/md)*md);
	return c<0?md+c:((ull)c>md?c-md:c);
}

struct Mat {
    ll v[55][55];
    Mat() {memset(v, 0, sizeof v);}
    Mat operator * (const Mat& b) const {
        Mat c;
        for(int k=0;k<=len;k++)
			for(int i=0;i<=len;i++)
				for(int j=0;j<=len;j++){
            c.v[i][j] = (qmul(v[i][k],b.v[k][j],m)+c.v[i][j])%m;
        }
        return c;
    }
    Mat operator ^ (ll nn) {
        Mat b, a=*this;
        for(int i=0;i<=len;i++)
			 b.v[i][i]=1;
        while(nn) {
            if(nn&1LL) b=b*a;
            nn>>=1LL,a=a*a;
        }
        return b;
    }
};

int main(void)
{
    scanf("%d",&t);
    while(t>0)
    {
        scanf("%lld %lld %s",&n,&m,s);
        len = strlen(s);
        gf();

        Mat g;
        for(int i=0;i<=len;i++)
			for(int k='a';k<='z';k++) {
            int nxt = i;
            while (nxt&&s[nxt]!=k) nxt = f[nxt];
            if (s[nxt]==k) ++nxt;
            if (i==len) nxt = len;
            ++g.v[nxt][i];
        }
        g = g^n;
        printf("%lld\n", g.v[len][0]);
        t--;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值