美文网首页程序员
641div2 - B. Orac and Models

641div2 - B. Orac and Models

作者: waaagh | 来源:发表于2020-05-23 23:04 被阅读0次

联想到最长递增序列,很快想到此题的dp,不过中间犯了两个错误。
一开始设dp[i]: 到i为止符合条件的最大序列数目,则
dp[i]=max \begin{cases} dp[i-1]& \text{i不选}\\ dp[k]+1& \text{s[k]<s[i]而且i%k==0,1<=k<i} \end{cases}
这个公式不对,原因在于dp[i]和dp[k]表示的意义不一样,dp[k]表示以k结尾的符合条件的最大序列数目。
因此重新设dp[i]: 以i结尾的符合条件的最大序列数目,则
dp[i]=max \begin{cases} dp[k]+1& \text{s[k]<s[i]而且i%k==0,1<=k<i} \end{cases}
最后选择dp[1]到dp[n]中的最大者即可,代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
using ll = long long;
int t, n;
int s[N];
int dp[N];
int main() {
    std::ios::sync_with_stdio(false);
    cin>>t;
    while(t--) {
        cin >> n;
        for(int i=1; i<=n; i++) {
            cin >> s[i];
        }
        memset(dp, 0, sizeof(dp));
        for(int i=1; i<=n; i++) {
            dp[i] = 1;
        }
        // 超时dp
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=i/2; j++) {
               if(i%j==0 && s[i]>s[j]) {
                   dp[i] = max(dp[i], dp[j]+1);
               } 
            }
        }
        int ans = 0;
        for(int i=1; i<=n; i++) {
            ans = max(ans, dp[i]);
        }
        cout << ans << endl;     
    }
    return 0;
}

结果超时,因复杂度O(n2),怎么能缩小j的范围呢?要保证j能整除i,是否可以让j以i, 2i, 3i...的方式循环?答案可以,正着推即可,代码如下:

       for(int i=1; i<=n; i++) {
           for(int j=i*2; j<=n; j+=i) {
               if(s[j]>s[i]) {
                   dp[j] = max(dp[j], dp[i]+1);
               }
           }
       

复杂度O(n\sqrt{n})。

相关文章

网友评论

    本文标题:641div2 - B. Orac and Models

    本文链接:https://www.haomeiwen.com/subject/qajrahtx.html