【CF 1061C|GOJ 3505】Multiplicity

传送门

  1. http://u.gdfzoj.com/problem/3505
  2. https://codeforces.com/problemset/problem/1061/C

解析

这题的复杂度要求我们需要使用线性作法(废话)。

考虑dp,如果 (i|b[i]),则它是一种方案,反之亦然。

所以有这么一个方程:

[f_{i,j} = left{ egin{array}{lr} f_{i,j} & , j ot|a_i\ f_{i,j}+f_{i-1,j-1} & , j|a_i end{array} ight. ]

该dp的时间复杂度为 (O(nmax(a_i))) 的,显然过不去,需要优化。

我们发现能取到第二条转移方程当且仅当 (j)(a_i) 的因数,而第一种第一种转移方程可以使用滚动数组直接省略掉。于是我们直接枚举 (a_i) 的因数,只在因数位置进行转移。同时注意因为 (i) 相同时的 (f)不能互相影响,所以对因数的转移要从大到小进行。好像01背包呀QAQ。

于是就可以轻松通过本题了。

#include<bits/stdc++.h>
namespace Bu_Yao_Tian_Tian_Bi_Sai {
	using namespace std;
#define LL long long
	inline LL read() {
		char c=getchar();
		LL sum=0;
		while(c<'0'||c>'9') {
			c=getchar();
		}
		while(c>='0'&&c<='9') {
			sum=(sum<<3)-'0'+(sum<<1)+c,c=getchar();
		}
		return sum;
	}
	inline void write(LL x) {
		if(x>9) {
			write(x/10);
		}
		putchar(x%10+'0');
	}
	const int d[4][2]= {
		{1,0},{0,1},{-1,0},{0,-1}
	},mod=1e9+7,N=1e5+5;
}
using namespace Bu_Yao_Tian_Tian_Bi_Sai;
int a[N],dp[N];
vector<int> v[N];
inline void chai(int x) {
	stack<int> sk;
	int tmp=a[x];
	for(int i=1; i*i<=tmp; i++) {
		if(tmp%i) {
			continue;
		}
		v[x].push_back(i);
		if(i*i^tmp) {
			sk.push(tmp/i);
		}
	}
	while(sk.size()) {
		v[x].push_back(sk.top()),sk.pop();
	}
}
int main() {
	int n=read();
	for(int i=1; i<=n; i++) {
		a[i]=read(),chai(i);
	}
	dp[0]=1;
	for(int i=1; i<=n; i++) {
		for(int j=v[i].size()-1; j>=0; j--) {
			int tmp=v[i][j];
			if(tmp<=n&&dp[tmp-1]) {
				dp[tmp]=(dp[tmp]+dp[tmp-1])%mod;
			}
		}
	}
	int ans=0;
	for(int i=1; i<=n; i++) {
		ans=(ans+dp[i])%mod;
	}
	write(ans);
	return 0;
}

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

限于本人水平,如果文章有表述不当之处,还请不吝赐教。

原文地址:https://www.cnblogs.com/Sam2007/p/12782525.html