• CF1061C Multiplicity


    题目传送门CF1061C

    洛谷入口

    题目大意

    (有个长度为n的序列a,你需要统计a中有多少个棒棒的子序列)
    (一个序列b被定义为棒棒的,当且仅当:)
    (对于序列中每一个位置i,b_i都能够被i整除)
    (答案对10^9+7 取模)

    数据范围

    (circ) (nle10^5)
    (circ) (1le a_ile10^6)

    题解

    这题可能是最近几道题里最简单的一道了
    不难想到暴力做法:
    (dp_{i,j}指枚举到i点,b序列长度为j的方案个数)
    (则状态转移方程是:)
    (dp_{i,j}=dp_{i-1,j}+(a_i)%(j==0) imes dp_{i-1,j-1})
    这样暴力的复杂度是(O(n^2))的,会超时
    于是考虑一下优化
    试着维护一下二维前缀和
    然后可以新添的长度(j要求是a_i)的因数
    于是可以试着枚举(a_i)的所有因数
    DP一下这个a[i]对所有因数(就是可能长度)的贡献(好吧本人蒟蒻难以准确说明,具体见代码吧)
    复杂度是根号级别的
    所以总复杂度就会是(O(nsqrt n))的了
    因为(n是10^5)的,于是可以3秒跑过了
    具体实现看下面代码↓↓↓

    AC代码:

    #include<bits/stdc++.h>
    #define ll  long long
    using namespace std;
    ll n,ans,mod=1e9+7;
    ll a[1000010],f[1000010];//用于dp的f[i]表示目前为止长度为i的合法序列个数 
    ll w[1000010];//存放a[i]的每一个因数 
    int main(){
    	cin>>n;
    	for(ll i=1;i<=n;++i)cin>>a[i];
    	f[0]=1;//为了使f能够合乎常理(?)地DP 
    	for(ll i=1;i<=n;++i){
    		ll qq=sqrt(a[i]),top=0;
    		for(ll j=1;j<=qq;j++){
    			if(a[i]%j==0){
    				w[++top]=j;
    				if(j*j!=a[i])//这句缺失会导致错误,如1,1,2->5就WA了 
    					w[++top]=a[i]/j;
    			}
    		}
    		sort(w+1,w+top+1);
    		for(ll j=top;j>=1;--j){
    			f[w[j]]=(f[w[j]]+f[w[j]-1])%mod;
    		}
    	}
    	for(ll i=1;i<=n;++i)ans=(ans+f[i])%mod;
    	cout<<ans;
    } 
    

    支持一下吧,关注,点赞,评论都好!

    THE END

    Reality&Imagine
  • 相关阅读:
    百度地图(8)-图层
    百度地图(7)-点聚合
    百度地图(6)-信息窗口
    鸟哥学习笔记二(基础篇第七章)
    鸟哥学习笔记一(基础篇第六章)
    sql server学习笔记二
    sql server学习笔记一
    centos下sudo命令不能使用
    CentOS系统时间与现在时间相差8小时解决方法
    SUID GUID详解
  • 原文地址:https://www.cnblogs.com/yang-RA-NOI/p/12595597.html
Copyright © 2020-2023  润新知