CF1061C Multiplicity 题解

本文重写于 2023.9.1

朴素的状态就设 \(f(i,j)\) 为考虑前 \(i\) 个数,选出了 \(j\) 个数的方案数。

有转移 \[ f(i,j) = \begin{cases} f(i-1,j)+f(i-1,j-1) & j \mid a_i \\ f(i-1,j) & j \nmid a_i \end{cases} \] 考虑优化。

空间的问题可以通过滚动数组解决。

注意到对于一个 \(i\),只有 \(j'\)\(i\) 的约数时才会从 \(j'\) 贡献到 \(j'+1\)。然后在 \([1,10^6]\) 的范围内,约数个数最多是 \(240\)

所以我们直接对每个 \(a_i\) 求约束集合,暴力从约数处转移过来就行。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
const int N=1e5+5, mod=1e9+7;
int n, a[N], f[N];
vector<int> divide(int x) {
	vector<int> factor;
	for(int i=1;i*i<=x;++i) if(x%i==0) {
		factor.pb(i);
		if(i*i!=x) factor.pb(x/i);
	}
	sort(factor.begin(),factor.end(),greater<int>());
	return factor;
}
signed main() {
	n=read();
	rep(i,1,n) a[i]=read();
	f[0]=1;
	rep(i,1,n) {
		vector<int> factor=divide(a[i]);
		for(auto x:factor) if(x<=i) (f[x]+=f[x-1])%=mod;
	}
	int ans=0;
	rep(i,1,n) (ans+=f[i])%=mod;
	printf("%lld\n",ans);
	return 0;
}

CF1061C Multiplicity 题解
https://yozora0908.github.io/2021/cf1061c-solution/
作者
yozora0908
发布于
2021年8月19日
许可协议