A 解锁专家
一开始看到这个A题的时候我的想法是直接DFS进行暴力搜索(因为没有注意到是多组输入),于是代码成功的TLE了。但是这个代码是一个很好的对拍代码!
然后手动写了几个数据发现好像前后之间存在一定的关联,于是我就用我TLE的代码进行打表去观察数据了
打表代码:
void dfs(int k) {
    if (k > n) {
        cnt++;
        return;
    }
    int pre = 0;
    if (k > 0)
        pre = k - 1;
    if (vis[pre]) {
        dfs(k+1);
    }
    else {
        vis[k] = 1;
        dfs(k+1);
        vis[k] = 0;
        dfs(k+1);
    }
}
 
然后成功发现了规律其实就是 F[i] = F[i-1] + F[i-2] + 1,再注意下离线打表就可以了
LL f[105];

void pre() {
    f[1] = 1;
    f[2] = 2;
    for (int i = 3;i <= 100; i++) {
        f[i] = f[i - 1] + f[i - 2] + 1;
        f[i] %= MOD;
    }
}

int main() {
    pre();
    int n;
    while (~scanf("%d",&n)) {
        printf("%lld\n", f[n]);
    }
    return 0;
}

B 麻烦的杰西
这个题应该是一个很有意思的题目。从题意来看我们很容易想得到我们应该找一个连续的区间,也就是找到左边界和右边界。但是我们如果采取暴力的方式去查找的话,那么这道题就会TLE (O(N^2))
但是其实当前 a[i] 的左边界是和 a[i-1] 的左边界有关系的,我们其实就是在 a[i-1] 的基础上去更新 a[i] 。这样算法复杂度就是O(N),有点类似于dp的思想。其实我们就是不断的向前去找就可以了。而对于右边界的话也是一样的,我们只要不断的向后去找就可以了。具体的还是看代码更好理解

int a[maxn],l[maxn],r[maxn];

int main() {
    int n;
    while (~scanf("%d",&n)) {
        for (int i = 1;i <= n;i++) {
            scanf("%d",&a[i]);
            l[i] = 0;
            r[i] = 0;
        }
        l[1] = 1;
        r[n] = n;
        for (int i = 2;i <= n;i++) {
            int t = i-1;
            if (a[i-1] >= a[i]) {
                while (t - 1 >= 1 && a[t-1] >= a[i])
                    t = l[t-1];
                l[i] = t;
            }
            else
                l[i] = i;
        }
        for (int i = n-1;i >= 1;i--) {
            int t = i+1;
            if (a[t] >= a[i]) {
                while (t + 1 <= n && a[t+1] >= a[i])
                    t = r[t+1];
                r[i] = t;
            }
            else
                r[i] = i;
        }
        LL ans = 0;
        int height = 0;
        for (int i = 1;i <= n;i++) {
            LL sum = (LL)a[i]*(r[i]-l[i]+1);
            if (sum > ans) {
                height = a[i];
                ans = sum;
            }
        }
        printf("%d %lld\n",height,ans);
    }
    return 0;
}

C 最大模数
其实就是一个二项式展开定理,如果把它展开了我们其实很容易发现答案其实就是 2 * (k * a)  k = ( 1,3,5,7,9...(2*n-1) )
然后我们只要不断的去找其中最大的那个就好了,然后其中也存在一些循环节,如果出现重复的我们就直接停止搜索了
int b[maxn];
int main() {
    LL a;
    b[0] = 1;
    b[1] = 3;
    for (int i = 2;i < maxn;i++) {
        b[i] = b[i-1] + 2;
        if (b[i] > 1000000)
            break;
    }
    while (~scanf("%lld",&a)) {
        LL sum = a * a;
        LL ans = 0;
        LL cnt = 0;
        for (int i = 0;i < maxn;i++) {
            if (i == 0)
                cnt = (2 * a * b[i]) % sum;
            ans = std::max(ans,(2*a*b[i]) % sum);
            if (i != 0 && ((2 * a * b[i]) % sum) == cnt)
                break;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

D 米多立亚
也算是一个规律题吧。我们其实只要发现 0 和 2 的相对位置是不会发生改变的,然后 1 都在第一个2 的前面 ,那么这题就过了
char ch[maxn];

int main() {
    while (~scanf("%s",ch)) {
        int len = strlen(ch);
        int cnt0 = 0,cnt1 = 0;
        for (int i = 0;i < len;i++) {
            if (ch[i] == '1')
                cnt1++;
        }
        for (int i = 0;i < len;i++) {
            if (ch[i] == '0')
                cnt0++;
            if (ch[i] == '2') {
                for (int j = 0;j < cnt0;j++)
                    printf("0");
                cnt0 = 0;
                for (int j = 0;j < cnt1;j++)
                    printf("1");
                cnt1 = 0;
                printf("2");
            }
        }
        for (int i = 0;i < cnt0;i++)
            printf("0");
        printf("\n");
    }
    return 0;
}

E 一步两步是魔鬼的步伐
典型的二分题目,一开始我想偏了,想成了贪心题目,结果贪到最后都没贪出来。 如果有人聚聚贪出来了,麻烦告诉我下思路
二分的话就是直接对答案进行二分,然后找到一个 符合题意 的最大的答案就好了

int a[maxn];
int L,N,M;

bool check(int k) {
    int last = 0,cnt = 0;
    for (int i = 1;i <= N+1;i++) {
        if (a[i] - last >= k) {
            last = a[i];
        }
        else
            cnt++;
    }
    if (cnt <= M)
        return true;
    else
        return false;
}

int main() {
    while (~scanf("%d%d%d",&L,&N,&M)) {
        for (int i = 1;i <= N;i++) {
            scanf("%d",&a[i]);
        }
        a[N+1] = L;
        std::sort(a+1,a+1+N);
        int l = 0,r = L;
        int ans = 0;
        while (l <= r) {
            int mid = (l + r ) >> 1;
            if (check(mid)) {
                ans = mid;
                l = mid + 1;
            }
            else
                r = mid - 1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

F 参赛
就是一个模拟题,然后注意一下特殊的就是不能最大化的拆,因为不一定会有教练

G 数数有多少个水坑
简单的方向DFS

H 你相信爱情吗
这也是一个规律题吧?感觉只要想到了 GCD 的话那么这题就不难了

I 师姐我想要红包
简单的DFS没什么好说的了

J 试试划水
 ans += cntz * cntu ,统计计数就好了

K 钟Sir的任务
暴力就好了

L JAJA_Xin的小心思
贪心