Educational Codeforces Round 76 7/7

想了想,本来一直都是打打cf,但是没有任何记录,感觉还是记录一下cf的补题比较好

A

#include <iostream>
 
using namespace std;
 
int main() {
	int T;
	cin >> T;
	while (T--) {
		int n, x, a, b;
		cin >> n >> x >> a >> b;
		if (a > b)
			swap(a, b);
		for (; x && a > 1; --x, --a);
		for (; x && b < n; --x, ++b);
		cout << b - a << '\n';
	}
}

B

#include <iostream>
#include <cstdio>
 
using namespace std;
 
using ll = long long;
 
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		int x, y;
		scanf("%d%d", &x, &y);
		ll t = x;
		for (int i = 1; i <= 100 && t < y; ++i) {
			if (t & 1)
				--t;
			t = t / 2 * 3;
		}
		if (t >= y)
			puts("YES");
		else
			puts("NO");
	}
}

C


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
 
using namespace std;
 
int const N = 200005;
 
int tot[N];
int a[N], n;
 
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &n);
		for (int i = 1; i <= n; ++i)
			tot[i] = 0;
		int ans = n + 1;
		for (int i = 1; i <= n; ++i) {
			scanf("%d", &a[i]);
			if (tot[a[i]])
				ans = min(ans, i - tot[a[i]] + 1);
			tot[a[i]] = i;
		}
		if (ans == n + 1)
			ans = -1;
		printf("%d\n", ans);
	}
}

D

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <utility>
 
using namespace std;
 
using ll = long long;
using pii = pair<int, int>;
 
int const N = 200005;
int const LOGN = 20;
 
int g[N][LOGN];
int f[N];
int b[N];
pii a[N];
int n, m;
int mx[N];
 
 
int RMQ(int l, int r) {
	int k = 0;
	while (1 << (k + 1) <= r - l + 1) 
		++k;
	int x = g[l][k], y = g[r - (1 << k) + 1][k];
	return b[x] > b[y] ? b[x] : b[y];
}
 
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &n);
		for (int i = 1; i <= n; ++i)
			scanf("%d", &b[i]);
		scanf("%d", &m);
		for (int i = 1; i <= m; ++i)
			scanf("%d%d", &a[i].second, &a[i].first);
		sort(a + 1, a + m + 1);
		mx[m + 1] = 0;
		for (int i = m; i >= 1; --i)
			mx[i] = max(mx[i + 1], a[i].second);
		if (mx[1] < *max_element(b + 1, b + n + 1)) {
			puts("-1");
			continue;
		}
 
		for (int i = 1; i <= n; ++i) 
			g[i][0] = i;
		for (int j = 1; (1 << j) <= n; ++j)
			for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
				int x = g[i][j - 1], y = g[i + (1 << (j - 1))][j - 1];
				g[i][j] = b[x] > b[y] ? x : y;
			}
 
		for (int i = 1; i <= n; ++i) {
			int l = 1, r = i - 1, pos = i;
			while (l <= r) {
				int mid = (l + r) >> 1;
				int jud = RMQ(i - mid, i);
				int p = lower_bound(a + 1, a + m + 1, pii{ mid + 1, 0 }) - a;
				//cerr << "E : " << i << ' ' << mid << ' ' << jud << ' ' << p << '\n';
				if (mx[p] >= jud) {
					pos = i - mid;
					l = mid + 1;
				} else
					r = mid - 1;
			}
			f[i] = f[pos - 1] + 1;
			//cerr << ">> " << i << ' ' << pos << ' ' << f[i] << '\n';
		}
		printf("%d\n", f[n]);
	}
}

E

DP,把每个位置看成分成0,1,2三组,等价于最小的代价,把序列变成递增的

#include <iostream>
#include <cstdio>
#include <algorithm>
 
using namespace std;
 
int const N = 200005;
 
int a[N], b[N], c[N], n1, n2, n3;
int f[N][3];
int t[N];
 
int main() {
	scanf("%d%d%d", &n1, &n2, &n3);
	int n = n1 + n2 + n3;
	for (int i = 1; i <= n1; ++i) {
		scanf("%d", &a[i]);
		t[a[i]] = 0;
	}
	for (int i = 1; i <= n2; ++i) {
		scanf("%d", &b[i]);
		t[b[i]] = 1;
	}
	for (int i = 1; i <= n3; ++i) {
		scanf("%d", &c[i]);
		t[c[i]] = 2;
	}
	for (int i = 1; i <= n; ++i) {
		f[i][0] = f[i - 1][0] + (t[i] != 0);
		f[i][1] = min(f[i - 1][0], f[i - 1][1]) + (t[i] != 1);
		f[i][2] = min(min(f[i - 1][1], f[i - 1][2]), f[i - 1][0]) + (t[i] != 2);
	}
	int ans = min(f[n][0], min(f[n][1], f[n][2]));
	printf("%d\n", ans);
}

F

meet-in-middle

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
 
using namespace std;
 
int const N = 100;
 
void solve(map<vector<int>, int>& mp, vector<int> const& a, int m, int off) {
	auto t = a;
	for (int i = 0; i < (1 << m); ++i) {
		for (int j = 0; j < (int)a.size(); ++j) 
			t[j] = __builtin_popcount(((a[j] >> off) ^ i) & ((1 << m) - 1));
		int mi = *min_element(t.begin(), t.end());
		for (auto& v : t)
			v -= mi;
		mp[t] = i << off;
	}
}
 
void debug_(pair<vector<int>, int> const& a, pair<vector<int>, int> const& b) {
	cerr << ">> " << a.second << ' ' << b.second << '\n';
	cerr << "A : ";
	for (auto const& v : a.first)
		cerr << v << ' ';
	cerr << '\n';
	for (auto const& v : a.first)
		cerr << __builtin_popcount(v ^ a.second) << ' ';
	cerr << '\n';
	cerr << "B : ";
	for (auto const& v : b.first)
		cerr << v << ' ';
	cerr << '\n';
	for (auto const& v : b.first)
		cerr << __builtin_popcount(v ^ b.second) << ' ';
	cerr << '\n';
}
 
int main() {
	int n;
	scanf("%d", &n);
	auto a = vector<int>(n, 0);
	for (auto& v : a)
		scanf("%d", &v);
	auto mp1 = map<vector<int>, int>();
	auto mp2 = map<vector<int>, int>();
	solve(mp1, a, 15, 0);
	solve(mp2, a, 15, 15);
	int ans = -1;
	for (auto const& p : mp1) {
		auto b = p.first;
		auto mx = *max_element(b.begin(), b.end());
		for (auto& v : b)
			v = mx - v;
		if (mp2.count(b)) {
			//debug_(p, pair<vector<int>, int>{ b, mp2[b] });
			ans = p.second | mp2[b];
			break;
		}
	}
	printf("%d\n", ans);
}

G

这题如果构建一个,首先按照素因子数量分层,最上面是素因子数量最多的数,然后每层往下面一层连边,如果下面的数是这个数的约数就连边,显然等价于找最长反链(话说我们代数学基础课的老师居然知道这个建图方式)。
然后最长反链等价于最小链覆盖,显然答案在最中间那层。(这个的证明可以考虑归纳一下,类似于证明 C ( n , p ) C(n, p) C(n,p)的最大的是 p = = n 2 p==\frac{n}{2} p==2n
然后这个就很简单了,把每个素因子看成一个生成函数,分治NTT卷一下就好。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <utility>
#include <vector>
#include <map>
 
using namespace std;
 
int const TT = 998244353, G = 3;
 
inline int KSM (int a, int k) {
	int ret = 1 % TT;
	for (; k; k >>= 1, a = 1ll * a * a % TT)
		if (k & 1)
			ret = 1ll * ret * a % TT;
	return ret;
}
 
inline int add (int x, int y) {
    if (x + y >= TT)
        return x + y - TT;
    else
        return x + y;
}
 
inline int sub (int x, int y) {
    if (x - y >= 0)
        return x - y;
    else
        return x - y + TT;
}
 
namespace Polynom
{
	vector<int> rev, rt, e = {1}, one = {1};
 
	vector<int> operator + (vector<int> f, vector<int> g) {
		int n = (int)max(f.size(), g.size());
		f.resize(n);
		g.resize(n);
		for (int i = 0; i < n; ++i)
			f[i] = add(f[i], g[i]);
		return f;
	}
 
	vector<int> operator - (vector<int> f, vector<int> g) {
		int n = (int)max(f.size(), g.size());
		f.resize(n);
		g.resize(n);
		for (int i = 0; i < n; ++i)
			f[i] = sub(f[i], g[i]);
		return f;
	}
 
	void getRevRoot (int n) {
		int m = log(n) / log(2) + 1e-7;
		rev.resize(n);
		rt.resize(n);
		for (int i = 1; i < n; ++i)
			rev[i] = rev[i >> 1] >> 1 | (i & 1) << (m - 1);
		for (int len = 1, uni; len < n; len <<= 1) {
			uni = KSM(G, (TT ^ 1) / (len << 1));
			rt[len] = 1;
			for (int i = 1; i < len; ++i)
				rt[i + len] = 1ll * rt[i + len - 1] * uni % TT;
		}
	}
 
	void NTT (vector<int> &f, int n) {
		f.resize(n);
		for (int i = 0; i < n; ++i) 
			if (i < rev[i])
				swap(f[i], f[rev[i]]);
		for (int len = 1; len < n; len <<= 1)
			for (int i = 0; i < n; i += len << 1)
				for (int j = 0, x, y; j < len; j++) {
					x = f[i + j];
					y = 1ll * f[i + j + len] * rt[j + len] % TT;
					f[i + j] = add(x, y);
					f[i + j + len] = sub(x, y);
				}
	}
 
	vector<int> operator * (vector<int> f, vector<int> g) {
		int n = 1, m = (int)f.size() + (int)g.size() - 1, ivn;
		while (n < m)
			n <<= 1;
		ivn = KSM(n, TT - 2);
		getRevRoot(n);
		NTT(f, n);
		NTT(g, n);
		for (int i = 0; i < n; ++i)
			f[i] = 1ll * f[i] * g[i] % TT;
		reverse(f.begin() + 1, f.end());
		NTT(f, n);
		f.resize(m);
		for (int i = 0; i < m; ++i)
			f[i] = 1ll * f[i] * ivn % TT;
		return f;
	}
 
	vector<int> polyInv (vector<int> f, int m) {
		if (m == 1)
			return { KSM(f[0], TT - 2) };
		f.resize(m);
		vector<int> g = polyInv(f, m >> 1), h;
		g.resize(m);
		h.resize(m);
		for (int i = (m >> 1) - 1; ~i; --i)
			h[i] = (g[i] << 1) % TT;
		int n = m << 1, ivn = KSM(n, TT - 2);
		getRevRoot(n);
		NTT(f, n);
		NTT(g, n);
		for (int i = 0; i < n; ++i)
			f[i] = 1ll * f[i] * g[i] % TT * g[i] % TT;
		reverse(f.begin() + 1, f.end());
		NTT(f, n);
		for (int i = 0; i < m; ++i)
			h[i] = sub(h[i], 1ll * f[i] * ivn % TT);
		return h;
	}
 
	vector<int> operator ~ (vector<int> f) {
		int n = 1, m = (int)f.size();
		while (n < m)
			n <<= 1;
		f = polyInv(f, n);
		f.resize(m);
		return f;
	}
 
	vector<int> polyDeri (vector<int> f) {
		if (f.empty())
			return f;
		int n = (int)f.size();
		for (int i = 1; i < n; ++i)
			f[i - 1] = 1ll * f[i] * i % TT;
		f.resize(n - 1);
		return f;
	}
 
	vector<int> polyInte (vector<int> f) {
		int n = (int)f.size();
		f.resize(n + 1);
		for (int i = n; ~i; --i)
			f[i] = 1ll * f[i - 1] * KSM(i, TT - 2) % TT;
		return f;
	}
 
	vector<int> polyLn (vector<int> f) {
		int n = (int)f.size();
		f = polyInte((~f) * polyDeri(f));
		f.resize(n);
		return f;
	}
 
	vector<int> polyExp (vector<int> f, int n) {
		if (n == 1)
			return one;
		f.resize(n);
		vector<int> g = polyExp(f, n >> 1);
		g.resize(n);
		return g * (one - polyLn(g) + f);
	}
 
	inline vector<int> polyExp (vector<int> f) {
		int n = 1, m = (int)f.size();
		while (n < m)
			n <<= 1;
		f = polyExp(f, n);
		f.resize(m);
		return f;
	}
 
	inline vector<int> operator ^ (vector<int> f, int x) {
		int n = 0, m = (int)f.size();
		while (n < m - 1 && !f[n])
			n++;
		f.erase(f.begin(), f.begin() + n);
		e = {KSM(f.empty() ? 0 : f[0], x)};
		f = polyLn(f);
		f.resize(n = max(0ll, m - 1ll * n * x));
		for (int i = 1; i < n; ++i)
			f[i] = 1ll * f[i] * x % TT;
		f = polyExp(f);
		reverse(f.begin(), f.end());
		for (int i = m - n; i; --i)
			f.push_back(0);
		reverse(f.begin(), f.end());
		f.resize(m);
		return f;
	}
 
	inline vector<int> operator / (vector<int> f, vector<int> g) {
		int n = f.size(), m = g.size();
		reverse(f.begin(), f.end());
		reverse(g.begin(), g.end());
		f.resize(n - m + 1);
		g.resize(n - m + 1);
		vector<int> ret = f * (~g);
		ret.resize(n - m + 1);
		reverse(ret.begin(), ret.end());
		return ret;
	}
 
	inline vector<int> operator % (vector<int> f, vector<int> g) {
		vector<int> ret = f / g;
		ret = f - (g * ret);
		ret.resize(g.size() - 1);
		return ret;
	}
} // namespace Polynom
 
using namespace Polynom;
 
vector<int> a_mul[200000 << 2];
 
void getMula (vector<int> const& a, int k, int l, int r) {
	if (l == r) {
		a_mul[k] = vector<int>(a[l] + 1, 1);
		return;
	}
	int mid = (l + r) >> 1;
	getMula(a, k << 1, l, mid);
	getMula(a, k << 1 | 1, mid + 1, r);
	a_mul[k] = a_mul[k << 1] * a_mul[k << 1 | 1];
}
 
int main () {
	int n;
	scanf("%d", &n);
	auto mp = map<int, int>();
	for (int i = 1; i <= n; ++i) {
		int x;
		scanf("%d" ,&x);
		mp[x]++;
	}
	int m = mp.size();
	auto a = vector<int>();
	for (auto p : mp)
		a.push_back(p.second);
	getMula(a, 1, 0, m - 1);
	cout << a_mul[1][n / 2] << '\n';
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值