Codeforces 1061C

给一个序列,找一个子序列,使得子序列中第i位的数能整除i,问能找到多少个子序列。
dp[i][j] 表示前i个数取得长度为j的子序列的个数
则dp[i][j] = dp[i-1][j] + (dp[i-1][j-1] if( a[i] % j == 0))可知i只和i-1有关系,故可以滚动起来
又 n 范围是1e5, n^2肯定TLE,进一步思考可知只有当a[i] %j == 0 时才需要更新,所以可以先把a[i]的因子都找出来,然后跟新这些因子即可。

#include <bits/stdc++.h>
using namespace std;

const int mod = 1e9 + 7;
int n,a[101010],mam,dp[1010110],ans; //dp[i] 表示长度为i的子序列的个数
vector <int> fact[1010101];	
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	//freopen("data.in","r",stdin);
	//freopen("data.out","w",stdout);
	cin>>n;
	for(int i = 1;i<=n;i++)	{
		cin>>a[i]; 
		mam = max(mam,a[i]);
	}
	for(int i = 1;i<=mam;i++)
		for(int j = 1;j<=mam/i;j++)
			fact[i*j].push_back(i);
	for(int i = 1;i<=n;i++)
		sort(fact[a[i]].begin(),fact[a[i]].end());
	dp[0] = 1; 
	for(int i = 1;i<=n;i++){
		 for(int j =fact[a[i]].size()-1;j>=0;j--){ 
		 	int x = fact[a[i]][j];
			dp[x] += dp[x-1];
			dp[x] %= mod;
		} 
	}	
	for(int i = 1;i<=n;i++) 
		ans += dp[i],ans %= mod;
	cout<<ans;		
	return 0;
}

猜你喜欢

转载自blog.csdn.net/winhcc/article/details/88979570