WolfDelaymasterHard

Topcoder #dp

\(\mathcal{O}(n^2)\)\(dp\) 是容易的

考虑怎么优化,注意到对于 \(x\) 这个位置,它能贡献到的区间是 \(log\)

因为每遇到一个 o ,合法的左端点都会从当前位置扩大到 \(2\) 倍,所以最多有 \(log\) 次扩大,即 \(log\) 个可以贡献到的段

// Author: xiaruize
const int N = 4e6 + 10;

int n, wlen, w0, wmul, wadd, olen, o0, omul, oadd;
int pre[N];
int nxtw[N], nxto[N];
char s[N];
int dp[N], f[N];

void init()
{
    cin >> n >> wlen >> w0 >> wmul >> wadd >> olen >> o0 >> omul >> oadd;
    rep(i, 1, n) s[i] = '?';
    int x = w0;
    rep(i, 0, wlen - 1)
    {
        s[x + 1] = 'w';
        x = (1ll * x * wmul + wadd) % n;
    }
    x = o0;
    rep(i, 0, olen - 1)
    {
        s[x + 1] = 'o';
        x = (1ll * x * omul + oadd) % n;
    }
}

void solve()
{
    init();
    dp[0] = 1;
    rep(i, 1, n * 2)
        nxtw[i] = nxto[i] = n + 1;
    rep(i, 1, n) pre[i] = (s[i] == 'w' ? i : pre[i - 1]);
    per(i, n, 1)
    {
        nxtw[i] = (s[i] == 'w' ? i : nxtw[i + 1]);
        nxto[i] = (s[i] == 'o' ? i : nxto[i + 1]);
    }
    rep(i, 0, n)
    {
        if (i)
            (f[i] += f[i - 1]) %= MOD;
        (dp[i] += f[i]) %= MOD;
        if (i % 2 == 0)
        {
            int x = i + 1;
            int nt = nxto[x];
            while (x < nt)
            {
                if (pre[x * 2 - i] <= x)
                {
                    int tmp = nxtw[x * 2 - i];
                    (f[x * 2 - i] += dp[i]) %= MOD;
                    (f[min((nt - 1) * 2 - i + 1, tmp)] += MOD - dp[i]) %= MOD;
                    x = tmp;
                }
                else
                    x = pre[x * 2 - i];
            }
        }
    }
    cout << dp[n] << endl;
}

#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif

signed main()
{
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int testcase = 1;
    // cin >> testcase;
    while (testcase--)
        solve();
#ifndef ONLINE_JUDGE
    cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
    cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
    return 0;
}
posted @ 2024-04-10 10:12  xiaruize  阅读(20)  评论(0)    收藏  举报