首页 > 其他分享 >[题解]CF1061C Multiplicity

[题解]CF1061C Multiplicity

时间:2024-06-23 22:34:30浏览次数:3  
标签:int 题解 复杂度 re Multiplicity Theta CF1061C bmod dp

题意

给定一个长度为 \(n\) 的序列 \(\{a_1,a_2,\dots,a_n\}\)。现在要在 \(a\) 选出非空子序列 \(\{b_1,b_2,\dots,b_m\}\),使得所有的 \(i \in [1,m]\),都有 \(b_i \bmod i = 0\)。

求能够选取 \(b\) 序列的方案数模 \(10^9 + 7\) 的值。

思路

定义 \(dp_{i,j}\) 表示在 \(\{a_1,a_2,\dots,a_i\}\) 中,选取 \(\{b_1,b_2,\dotsm,b_j\}\) 的方案数。

不难得出状态转移方程:

\[ dp_{i,j}\left\{\begin{matrix} dp_{i - 1,j} + dp_{i - 1,j - 1} & (a_i \bmod j = 0)\\ dp_{i - 1,j} & (a_i \bmod j \neq 0) \end{matrix}\right. \]

如果直接暴力 DP,时空复杂度均为 \(\Theta(n^2)\),过不了,考虑优化。

首先,可以滚动数组,使空间复杂度为 \(\Theta(n)\)。

然后,不难发现,对于 \(a_i\) 能产生贡献,当且仅当 \(a_i \bmod i = 0\)。

所以,对于我们 DP 过程中的 \(j\) 只能是 \(a_i\) 的因数。因此,可以在转移 \(dp_i\) 之前,求出 \(a_i\) 的因数,然后再转移即可。

时间复杂度 \(\Theta(n \sqrt{n})\);空间复杂度 \(\Theta(n)\)。

Code

#include <bits/stdc++.h>  
#define int long long  
#define re register  
  
using namespace std;  
  
const int N = 1e5 + 10,M = 1e6 + 10,mod = 1e9 + 7;  
int n,ans;  
int arr[N],dp[M];// DP 数组应该开 1e6,因为我们枚举的质因数有 1e6 的情况   
  
inline int read(){  
    int r = 0,w = 1;  
    char c = getchar();  
    while (c < '0' || c > '9'){  
        if (c == '-') w = -1;  
        c = getchar();  
    }  
    while (c >= '0' && c <= '9'){  
        r = (r << 3) + (r << 1) + (c ^ 48);  
        c = getchar();  
    }  
    return r * w;  
}  
  
signed main(){  
    dp[0] = 1;  
    n = read();  
    for (re int i = 1;i <= n;i++) arr[i] = read();  
    for (re int i = 1;i <= n;i++){  
        vector<int> v;  
        for (re int j = 1;j * j <= arr[i];j++){  
            if (arr[i] % j == 0){  
                v.push_back(j);  
                if (j * j != arr[i]) v.push_back(arr[i] / j);  
            }  
        }  
        sort(v.begin(),v.end(),[](auto const a,auto const b){  
            return a > b;  
        });//滚动数组应倒序更新   
        for (auto j:v) dp[j] = (dp[j] + dp[j - 1]) % mod;  
    }  
    for (re int i = 1;i <= n;i++) ans = (ans + dp[i]) % mod;  
    printf("%lld",ans);  
    return 0;  
}  

标签:int,题解,复杂度,re,Multiplicity,Theta,CF1061C,bmod,dp
From: https://www.cnblogs.com/WaterSun/p/18264019

相关文章

  • [题解]P2042 [NOI2005] 维护数列 - Splay解法
    P2042[NOI2005]维护数列一道思路不难,但实现细节很多的平衡树题,调了一天半终于做出来了w。对于初始序列,我们可以直接构建一条链(毕竟一个一个调用插入函数也可能形成一条链)。题解有递归直接构建成一棵严格平衡的二叉树的,这样也可以,常数可能会小一点。其中区间反转就是裸的文艺......
  • [MdOI R5] Many Minimizations & [ARC164F] Many Increasing Problems 题解
    讲下一个思路比较自然的基于自然数幂和的\(O(n\logn)\)且复杂度与\(m\)几乎无关的做法。不难发现让我们计数的问题是保序回归\(L_1\)中一条链的情况。这个情况有一个简单的slope-trick做法:用堆维护斜率,每次push进去两个当前的数,然后pop出一个最大值。最终所有数的和......
  • [MdOI R5] Many Minimizations & [ARC164F] Many Increasing Problems 题解
    讲下一个思路比较自然的基于自然数幂和的\(O(n\logn)\)且复杂度与\(m\)几乎无关的做法。不难发现让我们计数的问题是保序回归\(L_1\)中一条链的情况。这个情况有一个简单的slope-trick做法:用堆维护斜率,每次push进去两个当前的数,然后pop出一个最大值。最终所有数的和......
  • C++题解(1) 信息学奥赛一本通 1003:对齐输出 洛谷 B2004:对齐输出 土豆编程 T1003:对
    【题目描述】读入三个整数,按每个整数占8个字符的宽度,右对齐输出它们,按照格式要求依次输出三个整数,之间以一个空格分开。【输入】只有一行,包含三个整数,整数之间以一个空格分开。【输出】只有一行,按照格式要求依次输出三个整数,之间以一个空格分开。【输入样例】......
  • 一些东西 题解
    ATBAB设\(f_{i,0/1}\)表示\(i\)子树DFS序奇/偶位置和的最大值,首先如果\(i\)所有孩子的子树大小都是偶数,那访问这些孩子的顺序就无所谓了,否则考虑以\(i\)的至少一个大小为奇数的孩子为分界,对所有大小为偶数的孩子\(v\),把\(f_{v,0}\)更大的\(v\)、\(f_{v,1}\)......
  • [题解]CF311B Cats Transport
    思路首先,对于每一只小猫刚好玩完就被饲养员接走的出发时间必定为\(t_i-sd_i\)。那么,我们令\(a_i=t_i-sd_i\)表示第\(i\)只小猫的最早出发时间。因此,对于第\(k\)时刻出发的饲养员能接到的小猫当且仅当满足\(a_i\leqk\)。然后,我们定义\(dp_{i,j}\)表示用\(i\)......
  • [题解]CF245H Queries for Number of Palindromes
    思路定义\(dp_{i,j}\)表示区间\([i,j]\)中回文串的数量。那么,不难得出状态转移方程\(dp_{i,j}=dp_{i-1}+f_{i,j}\)。(其中\(f_{i,j}\)表示左端点大于等于\(i\),右端点为\(j\)的回文串数量)由此,现在问题转变为了如何求\(f_{i,j}\)。如果我们在求出了\(f_{i+1,j}......
  • [题解]CF154B Colliders
    思路首先我们将两种操作分开讨论:Part1加入操作那么,我们可以用一个数组\(vis_i=0/1\)表示\(i\)是关闭/开启状态,\(p_i\)表示因数有\(i\)的数。如果$vis_x=1$,说明此机器在之前已经启动过了,输出Success。然后,对\(x\)分解质因数,将质因数全部塞进一个集合\(a\)......
  • [题解]AT_dp_w Intervals
    思路首先考虑较为普通的DP。定义\(dp_{i,j}\)表示在前\(i\)个位置中,最后一个1在\(j\)的最大分数,显然有:\[dp_{i,j}=\left\{\begin{matrix}\max_{k=1}^{i-1}\{dp_{i-1,k}\}+\sum_{l_k\leqj\wedger_k=i}{a_k}&(i=j)\\dp_{i-1,j}+\sum......
  • [题解]AT_arc138_a [ARC138A] Larger Score
    思路不难发现:对于每一个\(i(1\leqi\leqk)\),如果能在\((k+1)\simn\)中找到任何一个\(j\),满足\(a_j>a_i\)就算满足条件。进一步思考,为了使操作数最小,对于每一个\(1(1\leqi\leqk)\),都找一个在\((k+1)\simn\)中第一个大于\(a_i\)的数,便于它交换。那么......