B:Arithmetic Progressions
题意:
给你一个长度为n的序列,问你这个序列中长度最长的等差数列长度为多少
题解:
方法一:将数组从小到大排序,n方扫,枚举出公差d,然后二分找有多少个满足等差序列的值即可,emmm虽然说不知道为什么这种最差复杂度为n^3*logn的暴力能过,可能是csuoj太快了吧。
代码:
#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = ;
const int maxn = 1e5 + ;
const int mod = 1e9 + ;
int n;
ll a[maxn];
int main() {
scanf("%d", &n);
for (int i = ; i <= n; i++) scanf("%lld", &a[i]);
sort(a + , a + + n);
int ans = ;
for (int i = ; i <= n; i++) {
for (int j = i + ; j <= n; j++) {
ll d = a[j] - a[i];
ll nxt = d + a[j];
int num = ;
int k = j;
while () {
k = lower_bound(a + k + , a + + n, nxt) - a;
if (a[k] != nxt) break;
nxt += d;
num++;
}
ans = max(ans, num);
}
}
printf("%d\n", ans);
return ;
}
方法二:由于不会暴力,于是就开始了dp
定义状态:
因为我们肯定要保存一个公差作为状态量,但是直接枚举又不现实。所以我们巧妙的设计出了这个状态,使得我们的公差就被表示了因此我们的转移就应该是在三个数中转移。即,,但是直接枚举也是不现实的根据等差数列的性质,若构成等差序列,那么所以转移就是每次转移更新答案即可我们枚举和,那么可以用双指针给处理出来从而让复杂度将为的级别
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = ;
const int INF = 0x3f3f3f3f;
int dp[maxn][maxn];
int a[maxn];
int main() {
int n;
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
}
sort(a + , a + n + );
int ans = ;
for(int i = ; i < n; i++) {
int j = i - ;
for(int k = i + ; k <= n && j; k++) {
while(j && a[j] + a[k] > a[i] + a[i]) {
j--;
}
if(j && a[j] + a[k] == a[i] + a[i]) {
if(dp[i][j] == ) {
dp[k][i] = ;
} else {
dp[k][i] = dp[i][j] + ;
}
ans = max(dp[k][i], ans);
}
}
}
cout << ans << endl;
}