zoukankan      html  css  js  c++  java
  • CF1061C Multiplicity(dp)

    洛谷传送门


    解题思路

    最朴素的 dp 为:(dp_{i,j}) 为前 (i) 个数选 (j) 个方案数。

    (O(n^2)) 的时空复杂度,很显然会炸,所以需要优化。

    先考虑空间,第一维可以滚动数组滚掉,因为选的第 (j) 个数与上一个数是什么没关系。

    再考虑时间上,尝试对于每个 (a[i])只枚举符合条件的 (j),即枚举其因数(根号复杂度)。

    注意:因为使用了滚动数组,所以因数要从大到小枚举

    题解中都是sort一遍,会多出一个log的复杂度,然而其实可以用一个栈一个队列维护。

    依次求出来的因数都是单调的(一个单调递增,一个单调递减),于是把较小的因数放到一个栈中,把较大的因数放到一个队列里,最后先遍历队列再遍历栈即可完成排序工作,这样就省掉了一个 log,在理论上也可以稳过了。

    所以最后时间复杂度就是 (O(nsqrt n))

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    const int maxn=1e6+5;
    const int mod=1e9+7;
    int n,a[maxn],dp[maxn],ans;
    queue<int> q;
    stack<int> s;
    template<class T>inline void read(T &x)
    {
        x=0;register char c=getchar();register bool f=0;
        while(!isdigit(c))f^=c=='-',c=getchar();
        while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
        if(f)x=-x;
    }
    int main(){
    	ios::sync_with_stdio(false);
    	read(n);
    	for(int i=1;i<=n;i++) read(a[i]);
    	dp[0]=1;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j*j<=a[i];j++){//求因数并省掉排序的log
    			if(a[i]%j==0){
    				s.push(j);
    				if(j*j!=a[i]) q.push(a[i]/j);
    			}
    		}
    		while(!q.empty()){//先遍历队列,再遍历栈,保证了单调递减
    			dp[q.front()]=(dp[q.front()]+dp[q.front()-1])%mod;
    			q.pop();
    		}
    		while(!s.empty()){
    			dp[s.top()]=(dp[s.top()]+dp[s.top()-1])%mod;
    			s.pop();
    		}
    	}
    	for(int i=1;i<=n;i++) ans=(ans+dp[i])%mod;
    	cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    Promise 对象
    [转] LVM分区在线扩容
    [转] 打开 CMD 时自动执行命令
    [转] FFmpeg常用基本命令
    systemd 之 journalctl
    systemd 之 systemctl
    关于用户权限的加强与理解(上)
    [转] 测试环境下将centos6.8升级到centos7的操作记录
    [搞机] 双网卡做数据均衡负载
    [转] 网络基础知识1:集线器,网桥,交换机
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15336333.html
Copyright © 2011-2022 走看看