Codeforces Round #523 (Div. 2)C. Multiplicity (dp+vector)

题目链接

C - Multiplicity

题意:

给定一个数组{a_k},问这个数组的所有子序列{b_k}中,有多少子序列满足:对于所有的i (1<=i<=k)满足 b_i是 i 的倍数,答案对10^9+7取模给定一个数组{{a_k}},问这个数组的所有子序列{b_k}中,有多少子序列满足:对于所有的i(1<=i<=k)满足 b_ii 的倍数,答案对10^9+7取模

题解:

先处理出a[i]的所有因数。
接着就是DP

dp[j] 长度为j的方案数

所以 dp[j]=dp[j]+dp[j-1]

j可以通过枚举a[i]的因数得到

别忘了 dp[j]%=mod

其中 在枚举所有因数的时候用到一个很巧妙的方法

用vector存储 (n*logn)的复杂度

vector<int> pr[1000005];
for(int i=1000000;i>=1;--i)
		for(int j=i;j<=1000000;j+=i)
			pr[j].push_back(i);

为什么要倒着存因子(从大到小存),因为它会重复加(我们只是用到了他最大的因子,其他的因子我们通过dp[i-1]获得)、

即 1 2 这两个数

1的因子只有1

2的因子有1 和 2

从小到大  dp[1]=0+dp[0]=0+1=1 ; dp[1]=dp[1]+dp[0]=1+1=2; dp[2]=0+dp[1]=2;

从大到小 dp[1]=0+d[0]=0+1=1; dp[2]=d[2]+d[1]=0+1=1; dp[1]=d[1]+dp[0]=1+1=2;

 

#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
vector<int> pr[1000005];
int dp[1000005], ans=0, n, x;
int main() {
	for(int i=1000000;i>=1;--i)
		for(int j=i;j<=1000000;j+=i)
			pr[j].push_back(i);
	dp[0]=1;
	cin>>n;
	for(int i=1;i<=n;++i) {
		cin>>x;
		for(auto x : pr[x])  dp[x]=(dp[x]+dp[x-1])%mod;
	}
	for(int i=1;i<=n;++i) ans=(ans+dp[i])%mod;
	cout<<ans<<endl;
	return 0;
}

改成一维的vector

#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long ll ;
const int MAX=1e6+10;
ll n,ans;
ll a[MAX];
ll dp[MAX];
int main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    dp[0]=1;
    for(int i=1;i<=n;i++)
    {
        vector<ll>v;
        for(int j=1;j*j<=a[i];j++)
        {
            if(a[i]%j==0)
            {
                v.push_back(j);
                if(j*j!=a[i])
                    v.push_back(a[i]/j);
            }
        }
        sort(v.begin(),v.end());
        reverse(v.begin(),v.end());
        for(auto &it: v)
        {
            dp[it]+=dp[it-1];
            dp[it]%=mod;
        }
    }
    for(int i=1;i<=n;i++)
        ans+=dp[i];
    ans%=mod;
    printf("%lld\n",ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值