zoukankan      html  css  js  c++  java
  • Gym101889J. Jumping frog(合数分解+环形dp预处理)

    比赛链接:传送门

    题目大意:

      一只青蛙在长度为N的字符串上跳跃,“R”可以跳上去,“P”不可以跳上去。

      字符串是环形的,N-1和0相连。

      青蛙的跳跃距离K的取值范围是[1, N-1],选定K之后不可改变。

      要求青蛙最后能跳回起点(起点可以是0-N-1的任意一个位置),问K的取值有多少种选择。

      3≤N≤105

    思路:

      考虑到如果gcd(N, K) = g,则从起点开始跳的话,所有经过的点都是g的倍数,而且每个g的倍数都会经过。

      所以只要考虑从任意一个点i开始,步长为g地跳,能不遇见"P"而跳到N+i的位置的话,那么这个K可以选。

      直接模拟的话就O(N2logN)了,考虑优化。

      因为对于确定的g,对应的有很多个K,而这些K的选与不选是确定的,所以考虑枚举g(其实就是N的约数),对每个g预处理出它是否能满足题意地完成条件。

      没记错的话约数的数量应该是logN级别的,所以环形dp预处理的复杂度为O(NlogN)。

      然后枚举一遍K,更新答案就可以了。

      复杂度O(NlogN + NlogN)。

    代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    const int MAX_N = 1e5 + 5;
    
    int N;
    char S[MAX_N];
    
    vector <int> factor;
    void getFactors(int N)
    {
        factor.clear();
        for (int i = 1; i <= N/i; i++) {
            if (N%i == 0) {
                factor.push_back(i);
                if (i*i != N)
                    factor.push_back(N/i);
            }
        }
        sort(factor.begin(), factor.end());
    }
    
    bool f[MAX_N << 1][50];
    bool can_jump[MAX_N];
    void dp()
    {
        int cnt = factor.size();
        memset(f, false, sizeof f);
        for (int i = 1; i <= 2*N; i++) {
            for (int j = 0; j < cnt; j++) {
                int tmp = factor[j];
                if (S[(i-1)%N] == 'P')
                    f[i][j] = false;
                else if (S[(i-1)%N] == 'R') {
                    if (i-tmp <= 0)
                        f[i][j] = true;
                    else
                        f[i][j] = f[i-tmp][j];
                }
            }
        }
    
        memset(can_jump, false, sizeof can_jump);
        for (int i = N+1; i <= 2*N; i++) {
            for (int j = 0; j < cnt; j++) {
                int tmp = factor[j];
                if (f[i][j])
                    can_jump[tmp] = true;
            }
        }
    }
    
    inline int gcd(int a, int b)
    {
        return a%b ? gcd(b, a%b) : b;
    }
    
    int main()
    {
        scanf("%s", S);
        N = strlen(S);
        getFactors(N);
        dp();
    
        int ans = 0;
        for (int k = 1; k <= N-1; k++) {
            int g = gcd(k, N);
            if (can_jump[g])
                ans++;
        }
        cout << ans << endl;
        return 0;
    }
    View Code
  • 相关阅读:
    JavaScript你所不知道的困惑(3)
    Android的代码都得自己一个个敲一遍吗?
    现代化农业在美国的兴起与发展
    高内聚与低耦合实现小记
    iOS 载入图片选择imageNamed 方法还是 imageWithContentsOfFile?
    swift笔记——环境搭建及Hello,Swift!
    HDU 4832(DP+计数问题)
    [TJOI2019]甲苯先生的线段树
    2019-8-31-C#-如何写-DEBUG-输出
    2019-8-31-C#-如何写-DEBUG-输出
  • 原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9980315.html
Copyright © 2011-2022 走看看