UESTC 第五届ACM趣味程序设计竞赛第四场(正式赛) 解题报告

本文只将我自己的解法公布,标准题解请等待官方正式题解报告

(暂无E题题解,欢迎补充)


Problem A Police and the Thief

博弈论 + 乱搞

首先我们定义Police和Thief之间的曼哈顿距离dis = |xp - xt| + |yp - yt|

作为一个聪明的小偷,他每次的行动会尽可能的使dis增大,而作为一个牛B的警察,他每次的行动会尽可能使dis减小

当然,由于小偷和警察的关系是小偷被警察追着跑

所以要使警察每次使dis-1并不难...

现在考虑小偷的面临的局面,若他在这个地图的非边界位置,他每次都可以使dis + 1,而警察会使dis - 1

若小偷在地图的边界位置上,小偷会遇到 不得不使dis - 1 ,而警察又会使dis - 1.

这样,dis - 2了

.......

在可预见的未来,我们知道,小偷和警察最后的位置应该只会有两种情况:

1.小偷和警察相邻;

2.小偷和警察对角相邻;(即在一个2*2的矩阵中,比如一个人在左上角,一个人在右下角,即为对角相邻)

现在我们考虑谁先手的问题。

若小偷先手,二者相邻的话,小偷是不会被抓住的;二者若对角相邻,反之。

同理可得警察先手的情况。

整体思路为上所述,但是还是要考虑一些特殊情况:1.二者一开始就在一起;2.地图的形状很特殊:n*1或1*m的


Problem B Similar strings

乱搞

对于长度不同的串我们暂且不讨论,一下讨论的为长度相同的串。

对于题目的意思,不妨定义为判断两个串的“模式”是否相同。

思路是将每个串都转换到一个数组里面,然后判断两个数组是否完全相同。

对于转换的方式,我们可以这样直接“离散化”(感觉差不多就这个意思)


Problem C The Game of Little P

贪心+数学+乱搞

为了得到最大的Score,我们容易得到这样的做法:能连Combo就连Combo,连不了就休息一回合再连下去,即我们说我们连“一套”Combo加一个休息为循环节

思路很简单,但是题目数据是很大的,几乎卡在了int的边界上面,所以求一套Combo的分数不能for了。

借用公式

求一套Combo的分数可以在O(1)时间内完成。

接下来是处理 mod 运算的方式,易知:(A * B) mod C = ((A mod C) * (B mod C)) mod C

但是感觉对于公式中,除以常数6是个很讨厌的地方,因为他不尽满足上述等式的性质。

故在计算一套Combo的值的时候,需要将除以6单独带入分子的表达式中验证哪个表达式(或哪两个表达式)是可以被其整除的。


Problem   DTrees

乱搞

对于输入的序列,我们先进行一边处理。

处理的方式是,我们首先假想有所有的Sequence都是基于以下模式的Sequence的:

1 2 3 4 …… 4 3 2 1

于是,我们不难想到,求出序列中,每棵树 对应上述Sequence 的 “距离”是多少(即达到这样的要求的差距)

这样,我们求出的每个“距离”,找出 拥有该距离最多的 树的数目 的即为应当保留不变的 树的数目

(其实抽象的来看,我们只是将斜面化成了平面就迎刃而解了)


下面附上代码:

Problem A

第一题代码有点瑕疵,其中注释前的部分是我比赛时提交通过的代码,注释后的是我比赛之后YY觉得应该改成那样的,主要看思路吧。

/*
 *  ID:     Allen_3
 *  Prob:   Police and the thief
 *  LANG:   C++
*/
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

const char THIEF[6] = "thief";

int T , n , m;
int xp , yp , xt , yt;
char str[20];

int main()
{
    scanf("%d" , &T);
    for (int i = 0;i < T;i ++)
    {
        scanf("%d%d" , &n , &m);
        scanf("%d%d%d%d" , &xp , &yp , &xt , &yt);
        scanf("%s" , str);
        int delta = abs(xp - xt) + abs(yp - yt);

        if ((xp == xt) && (yp == yt))
        {
            printf("YES\n");
            continue;
        }

        if (n == 1 || m == 1)
        {
            //if (delta % 2 == 0)
                printf("YES\n");
            /*
            else
                printf("NO\n");
            */
            continue;
        }

        if (strcmp(str , THIEF) == 0)
        {
            if (delta % 2 == 0)
                printf("YES\n");
            else
                printf("NO\n");
        }
        else
        {
            if (delta % 2 == 0)
                printf("NO\n");
            else
                printf("YES\n");
        }
    }   //for i _ T

    return 0;
}   //main

Problem B

/*
 *  ID:     Allen_3
 *  Prob:   Similar strings
 *  LANG:   C++
*/
#include<cstdio>
#include<cstring>
using namespace std;

int T;
int len_a , len_b;
char stra[100010] , strb[100010];
int arra[100010] , arrb[100010];
int hash[200];

int main()
{
    scanf("%d" , &T);
    for (int i = 0;i < T;i ++)
    {
        scanf("%s" , stra);
        scanf("%s" , strb);
        len_a = strlen(stra);   len_b = strlen(strb);
        if (len_a == len_b)
        {
            int tmpa = 0 , tmpb = 0;
            memset(hash , -1 , sizeof(hash));
            for (int i = 0;i < len_a;i ++)
            {
                if (hash[stra[i]] == -1)
                    hash[stra[i]] = tmpa ++;
                arra[i] = hash[stra[i]];
            }
            memset(hash , -1 , sizeof(hash));
            for (int i = 0;i < len_b;i ++)
            {
                if (hash[strb[i]] == -1)
                    hash[strb[i]] = tmpb ++;
                arrb[i] = hash[strb[i]];
            }
            bool flag = true;
            for (int i = 0;i < len_a;i ++)
                if (arra[i] != arrb[i])
                {
                    flag = false;
                    break;
                }
            if (flag)
                printf("YES\n");
            else
                printf("NO\n");
        }   //len_a == len_b
        else
            printf("NO\n");


    }   //for i _ T

    return 0;
}   //main

Problem C

/*
 *  ID:     Allen_3
 *  Prob:   The Game of Little P
 *  LANG:   C++
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;

#define     MOD     1000000007LL

#ifdef unix
#define     LL_FMT      "%lld"
#else
#define     LL_FMT      "%I64d"
#endif // unix

int T;
long long n , m;

void solve()
{
    long long ans = 0 , tmp;
    long long a = m * (m + 1) ;
    long long b = 2 * m + 1;
    bool flag1 = false , flag2 = false;

    if (!flag1 && (a % 2 == 0))
    {
        flag1 = true;
        a = a / 2;
    }
    if (!flag2 && (a % 3 == 0))
    {
        flag2 = true;
        a = a / 3;
    }
    if (!flag1 && (b % 2 == 0))
    {
        flag1 = true;
        b = b / 2;
    }
    if (!flag2 && (b % 3 == 0))
    {
        flag2 = true;
        b = b / 3;
    }

    tmp = ((a % MOD) * (b % MOD)) % MOD;

    long long ll = n / (m + 1) , mm;
    ans = (tmp * ll) % MOD;

    mm = n - ll * (m + 1);
    a = mm * (mm + 1); b = 2 * mm + 1;
    flag1 = false ; flag2 = false;

    if (!flag1 && (a % 2 == 0))
    {
        flag1 = true;
        a = a / 2;
    }
    if (!flag2 && (a % 3 == 0))
    {
        flag2 = true;
        a = a / 3;
    }
    if (!flag1 && (b % 2 == 0))
    {
        flag1 = true;
        b = b / 2;
    }
    if (!flag2 && (b % 3 == 0))
    {
        flag2 = true;
        b = b / 3;
    }

    tmp = ((a % MOD) * (b % MOD)) % MOD;

    ans = (ans + tmp) % MOD;
    printf(LL_FMT"\n" , ans);
}   //solve

int main()
{
    scanf("%d" , &T);
    for (int i = 0;i < T;i ++)
    {
        scanf(LL_FMT LL_FMT , &n , &m);
        solve();
    }   //for i _ T

    return 0;
}   //main

Problem D

/*
 *  ID:     Allen_3
 *  Prob:   Trees
 *  LANG:   C++
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;

int T , n;
int arr[100010];
int hash[300010];

void solve()
{
    memset(hash , 0 , sizeof(hash));
    for (int i = 0;i < (n >> 1);i ++)
    {
        arr[i] -= i;
        arr[n - i - 1] -= i;
    }   //for i _ n
    if (n & 1)
        arr[n >> 1] -= (n >> 1);

    for (int i = 0;i < n;i ++)
    {
        if (arr[i] > 0)
            hash[arr[i]] ++;
    }

    int ans = 0;
    for (int i = 0;i < n;i ++)
    {
        if (arr[i] > 0 && hash[arr[i]] > ans)
            ans = hash[arr[i]];
    }
    printf("%d\n" , n - ans);
}   //solve

int main()
{
    scanf("%d" , &T);
    for (int i = 0;i < T;i ++)
    {
        scanf("%d" , &n);
        for (int i = 0;i < n;i ++)
            scanf("%d" , &arr[i]);
        solve();
    }   //for i _ T

    return 0;
}   //main

Problem E

暂无


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值