zoukankan      html  css  js  c++  java
  • CF1061C Multiplicity

    题目传送门

    题目大意

    从序列(a_1,a_2,ldots,a_n)中选出非空子序列(b_1,b_2,ldots,b_k),一个子序列合法需要满足(∀iin[1,k],i|b_i)。求有多少互不相等的合法子序列,答案对(10^9+7)取模。

    思路

    一看到题,就会想起(dp),然后根据这类题的套路,就是设(f_{i,j})(a)序列的前(i)个数中长度为(j)的合法子序列有多少个。不难想到转移方程:

    [f_{i,j}=f_{i-1,j}+f_{i-1,j-1} imes[a_i%j==0] ]

    但是这样时间复杂度就是(O(ncdot max(a_i))),严重超时,所以考虑优化。

    因为第一维的(i)只和(i-1)有关,而且(j)要是(a_i)的因数,所以可以预处理出所有(a_i)的因数,第二维只用遍历(a_i)的因数就可以了。于是我们定义(f_i)为造了长度恰好为(i)的⼦序列的⽅案数(跟(a)序列的长度无关),(ys_{i,j})(a_i)的第(j)个因数,则转移方程如下:

    [f_{ys_{i,j}}=f_{ys_{i,j}}+f_{ys_{i,j}-1}(ys数组记录a_i的因数) ]

    这样子时间复杂度就是(O(nsqrt{a_i}{})),就可以过了。是不是很简单?

    代码

    #include<bits/stdc++.h>
    #define mod 1000000007
    using namespace std;
    vector<int> ys[100001];
    int n,a[100001],f[1000001],ans=0;
    int main() {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=sqrt(a[i]);j++){
    			if(a[i]%j==0){
    				ys[i].push_back(j);
    				if(j*j!=a[i]) ys[i].push_back(a[i]/j);
    			}
    		}
    	}
    	f[0]=1;
    	for(int i=1;i<=n;i++) {
    		for(int j=ys[i].size()-1;j>=0;j--){
    			f[ys[i][j]]=(f[ys[i][j]]+f[ys[i][j]-1])%mod;
    			ans=(ans+f[ys[i][j]-1])%mod;
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    

    不要忘记点个赞哦

    完结撒花

  • 相关阅读:
    编译和和运行amor
    用好C语言的中库,系统错误的处理
    C语言中的宏
    时隔多年,再次实现的链表
    脚本更改桌面背景
    python爬虫 一个security的RSA加密爬虫
    mysql 8.0版本
    mysql5.7的并行复制
    kinshard中间件问题
    Springboot2-@Transactional 事务不生效
  • 原文地址:https://www.cnblogs.com/LZY-LZY/p/12760581.html
Copyright © 2011-2022 走看看