CodeForces 1061C dpMultiplicity

参考:https://blog.csdn.net/wjl_zyl_1314/article/details/84503454

 Multiplicity
time limit per test3 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given an integer array a1,a2,…,an.

The array b is called to be a subsequence of a if it is possible to remove some elements from a to get b.

Array b1,b2,…,bk is called to be good if it is not empty and for every i (1≤i≤k) bi is divisible by i.

Find the number of good subsequences in a modulo 109+7.

Two subsequences are considered different if index sets of numbers included in them are different. That is, the values ​of the elements ​do not matter in the comparison of subsequences. In particular, the array a has exactly 2n−1 different subsequences (excluding an empty subsequence).

Input
The first line contains an integer n (1≤n≤100000) — the length of the array a.

The next line contains integers a1,a2,…,an (1≤ai≤106).

Output
Print exactly one integer — the number of good subsequences taken modulo 109+7.

Examples
input
2
1 2
output
3
input
5
2 2 1 22 14
output
13
Note
In the first example, all three non-empty possible subsequences are good: {1}, {1,2}, {2}
In the second example, the possible good subsequences are: {2}, {2,2}, {2,22}, {2,14}, {2}, {2,22}, {2,14}, {1}, {1,22}, {1,14}, {22}, {22,14}, {14}.

Note, that some subsequences are listed more than once, since they occur in the original array multiple times.
题意:
输入一个由n个数组构成的数列,现在从其中删除一些元素(但不能删完),要求删除后形成的新数列,满足每个位置的数值都能被整除下标。问有多少种删法能够得到满足条件的数列?(删法不同,即使最终结果相同也记为两种方法)
分析:

这一道题目是比较难处理的,但是仔细想一想,可以从因子入手,因为题目要求是可以放置x的地方下标必须可以整除嘛,所以,可以将其因子分解出来,但要注意处理4=2*2这样的情况;

然后就是推dp的状态转移方程:设当前的需要处理的数为9,那么其因子排序之后应是1、3、9

那么dp[9]=(dp[9]+dp[8])%mod;;;;;

dp[3]=(dp[3]+dp[2])%mod;;;;;;

。。。。。。。

为啥是这样子ni,可以去仔细想一想嘛,当发现当前这样下标出现,即当前这个位置是可以放数的,那么所有的组合情况不就是当前的位置有的个数+前一个位置有的个数;即dp[x]+=dp[x-1];这个意思就是说dp[x]的情况是由dp[x-1]推出的

感觉这个地方有点像01背包的降维优化的地方

#include<cstdio> 
#include<algorithm>
#include<cmath>
#include<iostream>
#include<map>
using namespace std;
const int N=2e5+100;
typedef long long ll;
const int INF=0x3f3f3f3f;
#define rep(i,a,b) for(int i=a;i<=b;i++)
const ll MOD=1e9+7;
ll dp[1001000];//存贮每一个位置的答案 
ll fac[1001000];//存储因子 
int n;
int main(){
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
    #endif
	scanf("%d",&n);
	dp[0]=1;//0这个位置什么也不放也就是一种情况 
	rep(i,1,n){ll x;
		scanf("%lld",&x);
		int tot=0,j=1;
		for(j=1;j<x/j;j++){
			if(x%j==0){
				fac[tot++]=j;
				fac[tot++]=x/j;
			}
		}
		if(x%j==0&&j==x/j)//这里是处理2*2=4 或者3*3=9这类特殊情况 
		fac[tot++]=x/j;
		sort(fac,fac+tot);
		for(j=tot-1;j>=0;j--){
			dp[fac[j]]+=dp[fac[j]-1]	;
			dp[fac[j]]%=MOD;
		}
	}
	ll ans=0;
	for(int i=1;i<=1000000;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、付费专栏及课程。

余额充值