ACM International Collegiate Programming Contest, Damascus University Collegiate Programming Contest(2018) 题解

签到题


A

4min 1Y

C

45min 3Y

题意

给两个串,要把第一个串变成第二个串。每次选择一个半径r,然后以第一个串的中心为中心,r为半径,左右翻转。问最少几次操作?

题解

细节有点多。

  • 先是输出-1的情况。这个很好考虑
  • 然后遍历s1串,对于位置i,如果需要翻转(s1[i]=s2[n+1-i]),则打上标记1,不需要翻转(s1[i]=s2[i]).则打上标记0,如果翻不翻转都可以(s1[i]=s1[n+1-i]),打上标记2。
  • 遍历[1,n/2],对于打上标记2的位置,我们要决定是翻还是不翻,根据贪心,我们可以怠惰一点!对于打上标记2的位置,和前一个位置保持一致即可。

F

25min 1Y

题解

统计一下每个数字出现了多少次,出现了x次,对答案的贡献则为x!,相乘即为答案。

J

42min 2Y

题解

按题意模拟。

冷静分析一下开局

  • 开场看了C觉得很基本,然后过了A,开始写C。
  • C细节没考虑清楚,用了10min,WA on test 2!
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 100000 + 10;
int T;
char s1[N], s2[N], s3[N];
bool ok[N];
int main() {
    scanf("%d", &T);
    while (T --) {
        scanf("%s %s", s1+1, s2+1);

        int n = strlen(s1+1);
        int mid = (n+1)/2;
        if (s1[mid] != s2[mid]) {
            printf("-1\n"); continue;
        }
        bool gg = 0;
        for (int i=1;i<mid;i++) {
            if (s1[i]==s2[i] && s1[n-i+1]==s2[n-i+1])
                ok[i] = 1;
            else if (s1[i]==s2[n-i+1] && s1[n-i+1]==s2[i])
                ok[i] = 0;
            else 
                gg = 1;
        }
        if (gg) {
            printf("-1\n"); continue;
        }

        int ans = 0;
        ok[0] = 1;
        for(int i=1;i<mid;i++) {
            if (ok[i] != ok[i-1])
                ans ++;
        }
        printf("%d\n", ans);
    }
}

完全没有考虑s1[i]=s1[n+1-i]的情况。

用了6分钟fix了一下。s1[i]=s1[n+1-i]

int ans = 0;
ok[0] = 1;
for(int i=1;i<mid;i++) {
    if (ok[i] != ok[i-1] && ok[i] != 2)
        ans ++;
}
printf("%d\n", ans);

然后喵了个呜,又一次WA2

  • 我逃跑,用了5min时间过了F
  • 用了10min的时间J题WA2
  • 用了5min的时间fix了一下,人调换方向那个地方写得意识有点模糊。
  • 用了2min时间fix了一下C,很沙比的错误,比如说n = 7,前3位,标记为0 2 0的情况就智障掉了。

前期比较容易细节没考虑清楚就上去写代码。C,J这两个模拟题都是这个原因吧。开始写代码之间,大概是抱着“随便搞搞就好”的想法。这种态度很沙比的啊。

  • 我在求什么?
  • 在模拟的过程,变量会如何变化?

这两个问题都考虑得不清楚吧!

中档题


B

Hash的做法很容易看出。然后就unlimited WA TLE MLE

搞Hash的经验严重不足?

边的种数不会超过n种,因此我们放n个桶。每个桶记录这种边出现的次数。

然后就是对一个XXX进制下,n位数的hash了【双hash保平安】

#include <iostream>
#include <algorithm>
#include <vector>
#include <unordered_map>

using namespace std;
typedef long long LL;

const int N = 10000008;
const LL MOD1 = 100000007;
const LL MOD2 = 923439347;

int T;
int n, x, y;
int val[N]; vector<int> v;
LL k1[N], k2[N];

unordered_map< LL, int > mp;

int main() {
    scanf("%d", &T);
    
    k1[0] = k2[0] = 1;
    for(int i=1;i<N;i++) {
        k1[i]=k1[i-1]*10007LL%MOD1;
        k2[i]=k2[i-1]*20007LL%MOD2;
    }
    while (T --) {
        scanf("%d", &n);
        v.clear();
        for (int i = 1; i <= n; i ++) {
            scanf("%d %d", &x, &y);
            if (x > y) swap(x, y);
            val[i] = (2*n+1)*x + y;
            v.push_back(val[i]);
        }
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
        for(int i=1;i<=n;i++) {
            val[i] = lower_bound(v.begin(), v.end(), val[i])-v.begin()+1;
        }
        mp.clear();
        LL sum1, sum2;
        LL ans=0;
        for (int i=1;i<=n;i++) {
            sum1 = 0, sum2 = 0;
            for(int j=1;j<=n;j++) {
                sum1 += k1[val[j]]; 
                sum1 %= MOD1;
                sum2 += k2[val[j]];
                sum2 %= MOD2;
            }
            mp[sum1*MOD2 + sum2] ++;
            for(int j=i+1;j<=n;j++) {
                sum1 += k1[val[j]]-k1[val[j-i]]; 
                sum1 = (sum1%MOD1+MOD1)%MOD1;
                sum2 += k2[val[j]]-k2[val[j-i]];
                sum2 = (sum2%MOD2+MOD2)%MOD2;
                mp[sum1*MOD2+sum2] ++;
            }
            for (auto x: mp) {
                LL v = x.second;
                ans += v * (v - 1) / 2;
            }
            mp.clear();
        }


        printf("%lld\n", ans);
    }
}

G

题意

修改最少的元素,使得序列的GCD为x,LCM为y。

题解

先判-1(一番激烈的讨论)

如果a[i]%x!=0 or y%a[i]!=0,那么i就是个卜。

直觉告诉我们把一个数字变成x,另一个数字变成y,只要其它的数字不卜,生活就有保障了。

  • 如果卜的个数>=2,那么答案就是卜的个数了。
  • 否则答案可能是1,可能是2,可能是0
  • 答案是0,很简单。
  • 答案是1,很不简单。我们枚举一下每个数字,看他是否能力挽狂澜,我们把枚举的数字放逐掉,求出其它数字的GCD&LCM(先预处理前缀后缀GCD&LCM),然后看一看世界末日前怎么办?来得及拯救吗?【具体怎么做,留给读者思考。】
  • 答案是2,很简单,加个else

I

题意

n堆石头,两种操作,两人轮流操作。

  • 可以从一堆石头中拿走一个石头。
  • 如果每堆石子都至少有1个,可以从每堆石头中拿走一个石头。

先手胜?后手胜?

题解

冷静分析一下

  • n%2=1. 易证,留给读者思考【读者似乎就我一个人。】
  • n%2=0. 这个得冷静分析一下。
  • min=1, 先手可以把后手气死。类似于chomp Game的模型。
  • min=2, 第一种操作肯定不可以施展的!不然会被气死。既然只能施展第二种操作,胜负显而易见了吧。
  • min=3, 先手可以把后手气死。类似于chomp Game的模型。
  • min=4, .......

博弈在模型的直觉很重要的吖!这题意识到了chomp Game就很简单了吧。

K

题意

n个点,n条边,多组查询,求两点间最短路。

题解

先去掉一条边edge,那么这个图就是一颗树了。

枚举,u到v是否要经过edge即可。

冷静分析一下中期

  • 先用了10min施展G,施展了一大半,然后咕咕咕了。
  • 先用了10min施展B题。没考虑清楚自己在hash什么东西,耽误了一段时间,然后WA11
  • 用了13min过了K。
  • 用了3min过了G的样例,WA2
  • 开始unlimited Fix G,中间用了很长一段时间次饭去了。但调G的时间至少有1小时。
    • Bug1:没读完就输出结果,WA
    • Bug2:复杂度nsqrt(n).【不错,有创意】
    • Bug3:n=1的特判不到位,搞得后面越界了。一大波RE。
  • 用了一个小时Fix B题的Hash,好不容易开始双hash然后MLE。枚举长度后清空,解决了问题。
  • 用了半个小时搞I

emmmm....大部分时间都在Fix辣鸡。。。

考虑清楚再写啊······

羊肉粉丝汤弱鸡啊。

感觉30min 4题,2h30min8题是比较合理的。


猜你喜欢

转载自www.cnblogs.com/RUSH-D-CAT/p/9119887.html