ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CLYZ-NOIP十连测 Day3

2021-10-03 13:04:28  阅读:161  来源: 互联网

标签:std NOIP get int Day3 ++ using CLYZ mx


CLYZ-NOIP2021 国庆集训 B 组 Day3

题面:https://files.cnblogs.com/files/blogs/575626/day3B.zip

头文字 A

我们考虑记下来到 \(n\) 的答案为 \(a_n\),那么我们可以得到一个显然的递推式

\[a_n=a_{n-1}+a_{n-2}+n-2 \]

然后这玩意直接用矩阵快速幂转移即可。

#include <bits/stdc++.h>
const int mod = 1e9 + 7;
inline int Mod(int x) {
	if (x >= mod) {
		return x - mod;
	}
	else {
		return x;
	}
}
using std::cin;
using std::cout;
int n;
struct Matrix {
	int a[4][4];
	Matrix() {
		memset(a, 0, sizeof a);
	}
	Matrix operator * (Matrix b) {
		Matrix ret;
		for (int i = 0; i < 4; ++i) {
			for (int k = 0; k < 4; ++k) {
				for (int j = 0; j < 4; ++j) {
					ret.a[i][j] = (ret.a[i][j] + (long long) a[i][k] * b.a[k][j]) % mod;
				}
			}
		}
		return ret;
	}
	Matrix operator ^ (int x) {
		Matrix ret;
		for (int i = 0; i < 4; ++i) {
			ret.a[i][i] = 1;
		}
		Matrix u = *this;
		for (; x; x >>= 1, u = u * u) {
			if (x & 1) {
				ret = ret * u;
			}
		}
		return ret;
	}
};
int main() {
	freopen("subset.in", "r", stdin);
	freopen("subset.out", "w", stdout);
	cin >> n;
	Matrix I;
	I.a[0][0] = 1;
	I.a[0][1] = 1;
	I.a[0][2] = 1;
	I.a[1][0] = 1;
	I.a[2][2] = 1;
	I.a[2][3] = 1;
	I.a[3][3] = 1;
	if (n < 3) {
		cout << 0 << '\n';
		return 0;
	}
	I = I ^ (n - 2);
	cout << Mod(I.a[0][2] + I.a[0][3]) << '\n';
	return 0;
}

头文字 B

这玩意,很明显首先求一个强连通分量,缩点,然后求的就是剩下的 \(DAG\) 上的最长链。

#include <bits/stdc++.h>
using std::cin;
using std::vector;
using std::pair;
using std::cout;
const int N = 1e6 + 10;
int n, m, dfc, dfn[N], low[N], num, col[N], top, stk[N], in[N], val[N], f[N];
vector<int> v[N], e[N];
template<typename T>
inline T min(const T &x, const T &y) {
	return x > y ? y : x;
}
template<typename T>
inline T max(const T &x, const T &y) {
	return x > y ? x : y;
}
void dfs(int u) {
	dfn[u] = low[u] = ++dfc;
	stk[++top] = u;
	for (auto &j: v[u]) {
		if (dfn[j]) {
			if (!col[j]) {
				low[u] = min(low[u], dfn[j]);
			}
		}
		else {
			dfs(j);
			low[u] = min(low[u], low[j]);
		}
	}
	if (low[u] == dfn[u]) {
		++num;
		while (!col[u]) {
			col[stk[top--]] = num;
			val[num]++;
		}
	}
	return;
}
int main() {
	freopen("bomb.in", "r", stdin);
	freopen("bomb.out", "w", stdout);
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	for (int i = 1, x, y; i <= m; ++i) {
		cin >> x >> y;
		v[x].push_back(y);
	}
	for (int i = 1; i <= n; ++i) {
		if (!dfn[i]) {
			dfs(i);
		}
	}
	for (int i = 1; i <= n; ++i) {
		for (auto &j: v[i]) {
			if (col[j] != col[i]) {
				e[col[j]].push_back(col[i]);
				in[col[i]]++;
			}
		}
	}
	std::queue<int> q;
	for (int i = 1; i <= num; ++i) {
		if (!in[i]) {
			q.push(i);
			f[i] = val[i];
		}
	}
	int ans = 0;
	while (q.size()) {
		int nw = q.front();
		q.pop();
		ans = max(ans, f[nw]);
		for (auto &j: e[nw]) {
			f[j] = max(val[j] + f[nw], f[j]);
			if (!--in[j]) {
				q.push(j);
			}
		}
	}
	cout << ans << '\n';
	return 0;
}

头文字 C

我们考虑这玩意肯定是底边最短的时候,层数最多。

那么考虑设计一个 \(dp\) 表示, \(f_i\) 表示 \([i...n]\) 中最下层的最短长度。

然后 \(f_i=\min_{j=i+1 \and sum_{j-1}-sum_{i-1}\ge f_j}^n sum_{j-1}-sum_{i-1}\)

这玩意的话,考虑直接用单调队列维护即可。

#include<bits/stdc++.h>
const int N = 100005;
int n, s[N], f[N], g[N], q[N], h, t;
int main() {
	freopen("block.in", "r", stdin);
	freopen("block.out", "w", stdout);
	scanf("%d", &n);
    h = t = 1;
    q[1] = n + 1;
    for (int i = 1, x; i <= n; i++) {
		scanf("%d", &x);
        s[i] = s[i - 1] + x;
	}
    for (int i = n; i >= 1; i--) {
        while (h < t && s[q[h + 1] - 1] - f[q[h + 1]] >= s[i - 1]) {
            h++;
		}
        f[i] = s[q[h] - 1] - s[i - 1];
        g[i] = g[q[h]] + 1;
        while (h <= t && s[i - 1] - f[i] >= s[q[t] - 1] - f[q[t]]) {
            t--;
		}
        q[++t] = i;
    }
    printf("%d\n", g[1]);
    return 0;
}

头文字 D

暴力想法,过了。

我们考虑,暴力维护这些东西,考虑维护一个数组 \(val_i\) 这个东西肯定是单调不增的,然后连续的段很多。维护这些连续段,考虑每次添加一个数会对于这玩意产生什么影响即可,就是枚举这个数的因数,看他之前在哪里出现,然后出现的位置到 \(i\) 这个区间里取 \(\max\) 即可。

这个取 \(max\) 操作最后可以用一个类似于归并操作的trick转化为 \(O(段数+d(a_i))\) 做一次。

最后枚举所有段数求答案即可。

时间复杂度看起来像是 \(n\log^2 n\) 的

#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::tuple;
using std::make_tuple;
using std::__gcd;
using std::get;
using std::pair;
using std::make_pair;
using std::cerr;
template<typename T>
inline T max(const T &x, const T &y) {
	return x > y ? x : y;
}
template<typename T>
inline T min(const T &x, const T &y) {
	return x < y ? x : y;
}
const int N = 1e5 + 10;
int n, a[N], pos[N];
long long cnt[N];
vector<int> d[N];
vector<tuple<int, int, int>> v;
int main() {
	freopen("gcd.in", "r", stdin);
	freopen("gcd.out", "w", stdout);
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> a[i];
	}
	for (int i = 1; i <= n; ++i) {
		for (int j = i; j <= n; j += i) {
			d[j].emplace_back(i);
		}
	}
	for (auto &j: d[a[1]]) {
		pos[j] = 1;
	}
	for (int i = 2; i <= n; ++i) {
		vector<tuple<int, int, int>> tmp, tmp1;
		vector<pair<int, int>> v1;
		for (int j = 0; j < d[a[i]].size(); ++j) {
			if (pos[d[a[i]][j]]) {
				v1.emplace_back(pos[d[a[i]][j]], d[a[i]][j]);
			}
		}
		std::sort(v1.begin(), v1.end(), std::greater<pair<int, int>> ());
		int last = i, mx = 0;
		for (auto &j: v1) {
			if (j.first < last && j.second > mx) {
				if (last != i) {
					tmp.emplace_back(mx, j.first + 1, last);
				}
				last = j.first;
				mx = j.second;
			}
		}
		v.insert(v.begin(), make_tuple(__gcd(a[i], a[i - 1]), i - 1, i - 1));
		tmp.emplace_back(mx, 1, last);
		int I = 0, J = 0;
		while (I < v.size() && J < tmp.size()) {
			if (get<0>(v[I]) >= get<0>(tmp[J])) {
				int mx = std::max(get<1>(v[I]), get<1>(tmp[J]));
				tmp1.emplace_back(get<0>(v[I]), mx, get<2>(v[I]));
				if (mx == get<1>(v[I])) {
					++I;
				}
				else {
					get<2>(v[I]) = mx - 1;
				}
				if (mx == get<1>(tmp[J])) {
					++J;
				}
				else {
					get<2>(tmp[J]) = mx - 1;
				}
			}
			else {
				int mx = std::max(get<1>(v[I]), get<1>(tmp[J]));
				tmp1.emplace_back(get<0>(tmp[J]), mx, get<2>(tmp[J]));
				if (mx == get<1>(v[I])) {
					++I;
				}
				else {
					get<2>(v[I]) = mx - 1;
				}
				if (mx == get<1>(tmp[J])) {
					++J;
				}
				else {
					get<2>(tmp[J]) = mx - 1;
				}
			}
		}
		v.clear();
		for (int i = 0; i < tmp1.size(); ++i) {
			if (!v.size()) {
				v.push_back(tmp1[i]);
			}
			else if (get<0>(v.back()) == get<0>(tmp1[i])) {
				get<1>(v.back()) = get<1>(tmp1[i]);
			}
			else {
				v.push_back(tmp1[i]);
			}
		}
		for (auto &j: v) {
			cnt[get<0>(j)] += get<2>(j) - get<1>(j) + 1;
		}
		for (auto &j: d[a[i]]) {
			pos[j] = i;
		}
	}
	for (int i = 1; i <= n; ++i) {
		cout << cnt[i] << '\n';
	}
	return 0;
}

标签:std,NOIP,get,int,Day3,++,using,CLYZ,mx
来源: https://www.cnblogs.com/siriehn-nx/p/15363912.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有