CF1061C 题解

题目链接

可爱的题目大意

有个长度为 \(n\) 的序列 \(a\),你需要统计 \(b\) 中有多少个棒棒的子序列。
一个序列 \(b\) 被定义为棒棒的,当且仅当:\(\forall i \in[1, k], i | b_{i}\)
答案对 \(10^9+7\) 取模。

\(Solution\)

卡常计数好题

因为这是dp专题里面的题,我们令 \(f_{i,j}\) 表示使用 \(a\) 中的前 \(i\) 个数字,组成了长度为 \(j\) 的子序列的方案数
那么显然有 \(f_{i,j}=f_{i-1,j}+f_{i-1,j-1} \times [j \, | \, a_i]\)
然后这样子是\(n^2\)的,显然\(TLE\),考虑优化时间复杂度
因为式子里面有这样一个东西:\([j \, | \, a_i]\),所以我们按套路枚举\(a_i\)的质因子\(j\),则:
\(f_{i,j}=\sum{f_{i,j-1}}\),其中\(j\)\(a_i\)的质因子
然后我们发现这其实是一个\(01\)背包的形式,于是考虑先找出\(a_i\)的所有质因子,从小到大排序后倒序\(dp\),这样可以滚动省掉一维空间


FBI Warning: 接下来是一个蒟蒻的错误,也许只有我一个人犯了,如果您不想在这上面浪费时间,可直接看到代码部分

一开始在\(gdfzoj\)上只有\(60pts\),在\(Codeforces\)上在第八个点\(T\)了,然后开始卡常
接下来先是把数组下标范围改了改,使\(memset\)的时间缩小\(10\)倍,再加上各种卡常套路,在\(Codeforces\)上过了,然鹅还是没有过\(gdfzoj\)\(1000ms\)毒瘤时限
最后发现其实那个\(memset\)是可以省掉的,因为后来的值会覆盖原来的
于是,血的教训:\(memset\)可能会增加时间复杂度的数量级(其实是只有我一个人才不知道吧。)


\(Code:\)

#include<bits/stdc++.h>
using namespace std;
namespace my_std
{
	typedef long long ll;
	typedef double db;
	#define pf printf
	#define pc putchar
	#define fr(i,x,y) for(register ll i=(x);i<=(y);++i)
	#define pfr(i,x,y) for(register ll i=(x);i>=(y);--i)
	#define go(x) for(ll i=head[u];i;i=e[i].nxt)
	#define mem0(a) memset(a,0,sizeof(a))
	#define meminf(a) memset(a,127,sizeof(a))
	#define enter pc('\n')
	#define space pc(' ')
	#define fir first
	#define sec second
	#define MP make_pair
	const ll inf=0x3f3f3f3f;
	const ll inff=1e15;
	inline ll read()
	{
		ll sum=0,f=1;
		char ch=0;
		while(!isdigit(ch))
		{
			if(ch=='-') f=-1;
			ch=getchar();
		}
		while(isdigit(ch))
		{
			sum=sum*10+(ch^48);
			ch=getchar();
		}
		return sum*f;
	}
	inline void write(ll x)
	{
		if(x<0)
		{
			x=-x;
			pc('-');
		}
		if(x>9) write(x/10);
		pc(x%10+'0');
	}
	inline void writeln(ll x)
	{
		write(x);
		enter;
	}
	inline void writesp(ll x)
	{
		write(x);
		space;
	}
}
using namespace my_std;
const unsigned long long N=1e5+50;
const unsigned long long mod=1e9+7;
ll n,a[N],d[N],f[N*10],dcnt,ans;
inline bool cmp(ll a,ll b){return a>b;}
int main(void)
{
	n=read();
	fr(i,1,n) a[i]=read();
	f[0]=1;
	fr(i,1,n)
	{
		dcnt=0;
		//memset(d,0,sizeof(d));
		fr(j,1,sqrt(a[i]))
		{
			if(a[i]%j!=0) continue;
			d[++dcnt]=j;
			if(j*j!=a[i]) d[++dcnt]=a[i]/j;
		}
		sort(d+1,d+dcnt+1,cmp);
		fr(j,1,dcnt) f[d[j]]=(f[d[j]]+f[d[j]-1])%mod;
	}
	fr(i,1,n) ans=(ans+f[i])%mod;
	writeln(ans);
	return 0;
}

完结撒花!!!

猜你喜欢

转载自www.cnblogs.com/lgj-lgj/p/12688436.html