zoukankan      html  css  js  c++  java
  • Gym 102082B : Arithmetic Progressions

    戳这里看题目吧!

    题目大意:给你一个长度为n(2<=n<=5000)的序列,没有重复的数字,序列中每个元素满足(0<=numi<=1e9)。求一个最长的数列满足差分值相同(除n=2外,可以看成等差数列)。输出这个最大长度。

    算法梗概:DP。看了几篇博客都说算是个板子套路DP题。在做的时候也想到了DP,但是没找对状态。

         另外可以用其他算法来做这道题,后面慢慢补。先给出DP算法的代码和思路。

     1 #include<cstdio>
     2 #include<algorithm>
     3 const int maxn = 5e3 + 5;
     4 int dp[maxn][maxn],n,num[maxn];
     5 int main()
     6 {
     7     scanf("%d",&n);
     8     for(int i=1;i<=n;++i){
     9         scanf("%d",num+i);
    10         for(int j=1;j<=n;++j){
    11             dp[i][j] = 2;
    12         }
    13     }
    14     std::sort(num+1,num+1+n);
    15     int ans = 2;
    16     for(int i=1;i<=n-1;++i){
    17         int pre = i - 1;
    18         for(int j=i+1;j<=n;++j){
    19           ///令d=num[j] - num[i],因为序列是递增的,所以num[i] - num[pre]在pre刚开始不满足条件时大于d,在pre刚好满足条件时等于d,继续遍历则小于d,后来的遍历是无意义的所以跳出即可
    20           while(pre > 0 && num[j] - num[i] > num[i] - num[pre]) pre--;
    21           if(pre==0) break;
    22           else if(pre > 0 && num[j] - num[i] == num[i] - num[pre]) dp[i][j] = std::max(dp[i][j],dp[pre][i]+1);
    23           ans = std::max(ans,dp[i][j]);
    24         }
    25     }
    26     printf("%d
    ",ans);
    27     return 0;
    28 }

    DP思路:dp[i][j]表示已下标ij(i<j)为结尾两个元素的一个子序列的长。枚举i,以i+1开始向后遍历j,这样对于每对ij我们可以求出他们的差,以这个差为标准,从i-1开始向前遍历记为pre,直到找到的preij满足num[j] - num[i] == num[i] - num[pre]。如果找到这样的num[pre]更新dp[i][j]即可。

    状态转移方程:dp[i][j] = max(dp[i][j],dp[pre][i]+1)


    直接用用等差数列的通项公式来暴力

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <set>
     4 using namespace std;
     5 const int maxn  = 5e3+50;
     6 int num[maxn],n;
     7 set<int> se;
     8 int main()
     9 {
    10     scanf("%d",&n);
    11     for(int i = 1; i<=n; ++i)
    12     {
    13         scanf("%d",num+i);
    14         se.insert(num[i]);
    15     }
    16     sort(num+1,num+n+1);
    17     int ans = 2,d,k;
    18     for(int i=1;i<=n;++i)
    19     {
    20         for(int j=i+1;j<=n;++j)
    21         {
    22             k = 2,d = num[j] - num[i];
    23             if(!se.count(num[i] + ans*d)) continue;
    24             while(se.count(num[i] + k*d)) k++;
    25             ans = max(ans,k);
    26         }
    27         if(ans==n) break;
    28     }
    29     printf("%d
    ",ans);
    30     return 0;
    31 }

    核心代码:

    1     k = 2,d = num[j] - num[i];
    2     if(!se.count(num[i] + ans*d)) continue;
    3     while(se.count(num[i] + k*d)) k++;
    4     ans = max(ans,k);

    暴力思路:ak = a1 + (k-1)d;

         两层for循环来枚举a1d,对于每对<a1,d>,枚举k来得到一个ak,判断ak是不是存在在序列中,存在继续枚举,否则更新答案。

    请注意!!!  if(!se.count(num[i] + ans*d)) continue; 这行代码的作用,对于你已经更新到的答案ans,如果num[i] + ans*d都不存在,那么无法更新答案,所以跳过这层循环。

    没有这行代码会TLE在test 57或者test 58,做题就死在了这里了。


    还有些同学用了二分函数,其实和暴力的核心思想差不多,用二分函数优化很多,这里只给代码,不解释了如果暴力看懂了这个也就懂了

     1 #include<cstdio>
     2 #include<algorithm>
     3 const int maxn = 5e3 + 5;
     4 int dp[maxn][maxn],n,num[maxn];
     5 int main()
     6 {
     7     scanf("%d",&n);
     8     for(int i=1;i<=n;++i) scanf("%d",num+i);
     9     std::sort(num+1,num+1+n);
    10 
    11     int ans = 2,res,d,pos;
    12     for(int i=1;i<=n-1;++i){
    13         for(int j=i+1;j<=n;++j){
    14             d = num[j] - num[i];
    15             res = 2;
    16             pos = std::lower_bound(num+j+1,num+n+1,num[i]+ans*d) - num;
    17             if(num[pos]!=num[i]+ans*d) continue;
    18             for(int k=j;k<=n-1;){
    19                 pos = std::lower_bound(num+k+1,num+n+1,num[k]+d) - num;
    20                 if(num[pos]==num[k]+d){
    21                     k = pos;
    22                     res++;
    23                 }
    24                 else break;
    25             }
    26             ans = std::max(ans,res);
    27         }
    28     }
    29     printf("%d
    ",ans);
    30     return 0;
    31 }

    This’s all!如有错误,请评论指正谢谢!!

  • 相关阅读:
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 Cowboys
    Java实现 蓝桥杯 算法训练 Cowboys
    55. Jump Game
    54. Spiral Matrix
    50. Pow(x, n)
  • 原文地址:https://www.cnblogs.com/chen-tian-yuan/p/11373077.html
Copyright © 2011-2022 走看看