CF1529D

规律,结论

不妨假设现在有三种长度的区间 \(A,B,C\) ,其中 \(A<B<C\)

lemma:

  1. 每一个B区间必包含所有A区间,每一个C区间必包含所有B区间(每一个大的区间,必包含所有小的区间)

    proof:显然

  2. 所有A区间包含的点集必连续,所有A,B区间包含的点集必连续(长度小于等于某一个数的所有区间包含的点集必连续)

    proof:以假设为例。不妨设A不连续,存在一点x,使得其左右都由A的点集中的点,但它不属于A的点集。

    ​ Then,不难发现此情况一定不满足题意。若此点为B的右端点之一,显然右边有A,否则左边有A。

  3. A区间最左的左侧剩余的点数一定等于最右的右侧剩余的点数(长度小于等于某一个数的所有区间包含的点集一定有左剩余等于右剩余)

    proof:所有比A更大的区间要包含A这一段连续的区间,所以必定左边有一个点右边有一个点。

Solution:

​ 设 \(dp_n\) 为 n 的答案,记 \(D_x\) 为数 x 的因数个数(包含1和本身)

​ 当 n 仅由一种长度的区间构成时,不难发现此时贡献为 \(D_n\)

​ 当 n 由两种长度的区间构成时。考虑lemma2,3,不难发现贡献为 所有小于n的且由一种长度的区间构成 的答案之和(此时更大的长度一左一右覆盖所有更小的区间)

​ 当 n 由三种长度的区间构成时。同上,能发现贡献为 所有小于n的且由两种长度的区间构成 的答案之和(此时最大的长度一左一右覆盖所有更小的区间)

​ ......

​ 综上易得

\(dp_n = \Sigma_1^n dp_{i}+D_n\)

Code:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ll long long
#define ull unsigned long long
#define cint const int&
#define Pi acos(-1)

const int mod = 998244353;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;

int to[1001000];
bool vis[1001000];

ll ans[1001000];
ll pre[1001000];
int n;

void init() {
    for(int i=2; i<=1000000; i++) if(!vis[i])
        for(int j=1; i*j<=1000000; j++) {
            vis[i*j] = 1;
            to[i*j] = i;
        }
}

ll sol(int x) {
    int tmp = 0, la = 0;
    ll ans = 1;
    while(x) {
        if(to[x] != la) {
            ans *= (tmp+1);
            tmp = 0;
            la = to[x];
        }
        if(x == 1) break;
        x /= la;
        ++tmp;
    }
    return ans;
}

int main() {
    init();
    cin >> n;
    for(int i=1; i<=n; i++) {
        ans[i] = (pre[i-1]+sol(i)) % mod;
        pre[i] = (pre[i-1]+ans[i]) % mod;
    }
    cout << ans[n] << endl;
    return 0;
}
posted @ 2021-05-29 13:52  ullio  阅读(40)  评论(0编辑  收藏  举报