B. Orac and Models(1350B)(dp + 因数分解)

B. Orac and Models(1350B)(dp + 因数分解)

来源:B. Orac and Models


题意:

给一个长度为 n 的数组 x,查找一个最长的序列,该序列满足在数组 x 中的下标 i1 < i2,i2 % i1 == 0,且 x[i1] < x[i2]


思路

用 f 数组记录,f[i] 表示以 x[i] 结尾的最长序列长度。

那么每次我们只需要从 x 数组中找到下标是 i 的因子且不为 i ,是否小于 x[i],那么 f[i] = max(f[i], f[index] + 1)。而每个数的因子我们可以先预处理出来。

a[1] 到 a[k] 的和等于a[2] 到 a[k + 1] 的和,说明a[1] == a[k + 1],所以任意两个长度为k的字段排序后全都相等。那么当数组中数的种类大于k时,一定不能构造,小于等于k时,进行n此操作,每次操作将这k种数按出先的顺序先输出一遍,之后任意补充元素补够k个即可。

代码:

#include 
#define endl "\n"
#define debug(a) cout << #a << " = " << a << endl;
#define rep(i, m, n) for (int i = (m); i <= (n); ++i)
#define rrep(i, m, n) for (int i = (m); i >= (n); --i)
#define IOS ios::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 10, mod = 1e9 + 7;
int n, x[N];
int f[N];
vector<int> v[N];
void init(int n = N - 10) {
	rep(i, 1, n) for (int j = 2; ; ++j) {
		if (i * j > n) break;
		v[i * j].push_back(i);
	}
}
void solve() {
	scanf("%d", &n);
	memset(f, 0, sizeof(int) * (n + 1));
	rep(i, 1, n) scanf("%d", &x[i]);

	rep(i, 1, n) for (auto& op : v[i])
		if (x[i] > x[op])
			f[i] = max(f[i], f[op] + 1);

	int ans = 0;
	rep(i, 1, n) ans = max(ans, f[i]);
	printf("%d\n", ans + 1);
}
int main() {
	init();
	int t; cin >> t;
	while (t--) solve();
	return 0;
}

END

你可能感兴趣的:(CF)