Problem Description
Avin is studying series. A series is called "wave" if the following conditions are satisfied:
1) It contains at least two elements;
2) All elements at odd positions are the same;
3) All elements at even positions are the same;
4) Elements at odd positions are NOT the same as the elements at even positions.
You are given a series with length n. Avin asks you to find the longest "wave" subseries. A subseries is a subsequence of a series.
埃尔文在学习序列。一个“波浪数组”(摆动数组)要满足以下条件:
1 包含至少两个元素(最多也是)
2 所有奇数位元素相同
3 所有偶数位元素相同
4 奇数位和偶数位元素不同
给定一个n长度的序列,埃尔文要求你去寻找最长的波浪子数组,一个子数组是序列的子序列。
Input
The first line contains two numbers n, c (1 ≤ n ≤ 100, 000, 1 ≤ c ≤ 100). The second line contains n integers whose range is [1, c], which represents the series. It is guaranteed that there is always a "wave" subseries.
Output
Print the length of the longest "wave" subseries.
Sample Input
5 3 1 2 1 3 2
Sample Output
4
由于本题关键变量c的数据范围较小,所以为此题提供了一种暴力解题的可能性。换句话说,只需要从序列中找到两个数字,使得它们构成的波浪数组最长即可。
表面上看复杂度是n*c*c(位置与枚举),达到了10的九次方,但是在一次仅有两个数字需要关心,所以直接记录这两个数字的位置,跳过其他数字即可。那么就可把n优化为n/c(需遍历长度),将复杂度降为nc,10的七次方,可在1秒内结束运行。
在遍历n/c长度的数组时,我们还得确定一个先后的问题,也就是得记录一下前一个数字最后出现的位置。
所以思路如下:
- 利用vector或者其他东西,存储各个数字在序列中出现的位置
- 利用枚举循环,在这些数字存在的位置中遍历即可。
//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll lldcin()
{
ll tmp = 0, si = 1;
char c;
c = getchar();
while (c > '9' || c < '0')
{
if (c == '-')
si = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
tmp = tmp * 10 + c - '0';
c = getchar();
}
return si * tmp;
}
///Untersee Boot IXD2(1942)
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
/**Last Remote**/
vector<ll>vec[500];
int DETERMINATION()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
ll n, c;
cin >> n >> c;
ll tmp;
for (int i = 1; i <= n; i++)
{
cin >> tmp;
vec[tmp].push_back(i);
}//这里是记录各个数字出现的位置
ll ans = 0;
for (int i = 1; i <= c; i++)
{
for (int j = 1; j <= c; j++)//枚举范围内数字
{
if (i == j)
continue;
ll iloc = 0, jloc = 0, previous = 0, tmpans = 0;
ll ilimit = vec[i].size(), jlimit = vec[j].size();
//cout << i << " " << j << endl;
while (1)//进行遍历
{
while (iloc < ilimit&&vec[i][iloc] < previous)//在先前位置之后,找到一个目标数字的合法位置
iloc++;
if (iloc == ilimit)
break;
else
{
previous = vec[i][iloc];//更新先前位置
tmpans++;
}
while (jloc < jlimit&&vec[j][jloc] < previous)
jloc++;
if (jloc == jlimit)
break;
else
{
previous = vec[j][jloc];
tmpans++;
}
}
ans = max(tmpans, ans);
}
}
cout << ans << endl;
return 0;
}
当然,暴力解题只是侥幸。正规的做法是对两个c范围内的数字所能组成的波浪数组的最大值列状态转移方程。啥意思?就是对整个序列出现的数字按照次序全部记录下来,然后从原序列中逐一遍历数字,通过状态转移方程找到这两个数字可组成的波浪数组的长度的最大值。
这里的状态转移方程只是代表了某两个数字可组成多长的波浪数组,因此用二维数组即可。
所以思路如下:
- 存储每个数字的出现次序
- 以原序列和存储数组作两层循环,利用状态转移方程找到最大值。
//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll lldcin()
{
ll tmp = 0, si = 1;
char c;
c = getchar();
while (c > '9' || c < '0')
{
if (c == '-')
si = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
tmp = tmp * 10 + c - '0';
c = getchar();
}
return si * tmp;
}
///Untersee Boot IXD2(1942)
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
/**Last Remote**/
ll dp[250][250], secq[530000], vis[5000];
ll a[650000];
int DETERMINATION()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
ll n, c;
cin >> n >> c;
ll cnt = 0;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (vis[a[i]] == false)
{
secq[++cnt] = a[i];//存储它的出现次序
vis[a[i]] = true;//已经出现在存储数组里了,就没必要再存储了
dp[0][a[i]] = 1;//至少就他自己而言,可以组成1个长度的波浪数组,不符题意但是存在
}
}
ll ans = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= cnt; j++)
{
if (a[i] != secq[j])//这两个数不能一样
{
ll tmp = max(dp[0][secq[j]] + 1, dp[a[i]][secq[j]] + 1);//看这个数是新创建了一个波浪数组还是在原有的波浪数组上延长
dp[secq[j]][a[i]] = max(tmp, dp[secq[j]][a[i]]);
//反过来也一样
ans = max(dp[secq[j]][a[i]], ans);
}
}
}
cout << ans-1 << endl;
return 0;
}