網易2018校招內推編程題_小易喜歡的數列

[編程題] 小易喜歡的數列

時間限制:1秒

空間限制:32768K

小易非常喜歡擁有以下性質的數列:
1、數列的長度爲n
2、數列中的每個數都在1到k之間(包括1和k)
3、對於位置相鄰的兩個數A和B(A在B前),都滿足(A <= B)或(A mod B != 0)(滿足其一即可)
例如,當n = 4, k = 7
那麼{1,7,7,2},它的長度是4,所有數字也在1到7範圍內,並且滿足第三條性質,所以小易是喜歡這個數列的
但是小易不喜歡{4,4,4,2}這個數列。小易給出n和k,希望你能幫他求出有多少個是他會喜歡的數列。 
輸入描述:
輸入包括兩個整數n和k(1 ≤ n ≤ 10, 1 ≤ k ≤ 10^5)


輸出描述:
輸出一個整數,即滿足要求的數列個數,因爲答案可能很大,輸出對1,000,000,007取模的結果。

輸入例子1:
2 2

輸出例子1:
3
毫無疑問,dp。
dp[i][j] 表示當數列個數爲 i 個時,以 j 結尾有多少個符合要求的數列。
dp[i][j] = dp[i-1][k] 的和( k<=j | | k%j!=0 )
這樣時間複雜度是O(n*k^2) ,超時。
優化,既然 dp[i-1][k] 這個要累加的次數比較多,那麼我們就把他的和在上一次求解中先求出來,然後進行累減就行了。
優化後,dp[i][j] = pre_i_total - dp[i-1][k] (k>j&&k%j==0)
時間複雜度O(n*k*logk)
        #include<iostream>
        #include<cstdio>
        #include<cstring>
        using namespace std;
        typedef long long ll;
        ll dp[15][100005];
        const ll mod=1e9+7;
        
        int main()
{
	    ll n,k;
	    while(scanf("%lld%lld",&n,&k)==2)
	    {
	    	memset(dp,0,sizeof(dp));
	    	ll pre_i_total=0,nex_i_total=0;
	    	for(int i=1;i<=n;i++)
	    	{
	    	 	for(int j=1;j<=k;j++)
	    	 	{
	    	 		ll ad=pre_i_total;
	    	 		for(int u=2;u*j<=k;u++)
	    	 			ad=dp[i-1][u*j]>ad?ad+mod-dp[i-1][u*j]:ad-dp[i-1][u*j];
	    	 			
	    	 		if(i==1) dp[i][j]=1;
	    	 		else dp[i][j]=ad%mod;
	    	 		nex_i_total=(nex_i_total+dp[i][j])%mod;
				}
				pre_i_total=nex_i_total;
				nex_i_total=0;
			}
			ll ans=0;
			for(int u=1;u<=k;u++) ans=(ans+dp[n][u])%mod;
			printf("%lld\n",ans);
		}     
		return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章