Educational Codeforces Round 142 (Rated for Div. 2)

E.

题意:给定n*n乘法表和m=m1*m2,求乘法表中出现多少个m的约数,最早出现的行数分别是多少.

对m1,m2分解质因数,然后dfs搜出所有m的约数,然后子集dp,设f[i]为小于m最大的约数,初始化f[i]=i,(i <=m),转移f[i] = max(f[i], f[i / p]),最后判断i / f[i]是否小于等于m即可.

#include <bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0) 
#define ll long long 
// #define double long double
#define ull unsigned long long 
#define PII pair<int, int> 
#define PDI pair<double, int> 
#define PDD pair<double, double> 
#define debug(a) cout << #a << " = " << a << endl 
#define point(n) cout << fixed << setprecision(n)
#define all(x) (x).begin(), (x).end() 
#define mem(x, y) memset((x), (y), sizeof(x)) 
#define lbt(x) (x & (-x)) 
#define SZ(x) ((x).size()) 
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
// namespace nqio { const unsigned R = 4e5, W = 4e5; char* a, * b, i[R], o[W], * c = o, * d = o + W, h[40], * p = h, y; bool s; struct q { void r(char& x) { x = a == b && (b = (a = i) + fread(i, 1, R, stdin), a == b) ? -1 : *a++; } void f() { fwrite(o, 1, c - o, stdout); c = o; } ~q() { f(); }void w(char x) { *c = x; if (++c == d) f(); } q& operator >>(char& x) { do r(x); while (x <= 32); return *this; } q& operator >>(char* x) { do r(*x); while (*x <= 32); while (*x > 32) r(*++x); *x = 0; return *this; } template<typename t> q& operator>>(t& x) { for (r(y), s = 0; !isdigit(y); r(y)) s |= y == 45; if (s) for (x = 0; isdigit(y); r(y)) x = x * 10 - (y ^ 48); else for (x = 0; isdigit(y); r(y)) x = x * 10 + (y ^ 48); return *this; } q& operator <<(char x) { w(x); return *this; }q& operator<< (char* x) { while (*x) w(*x++); return *this; }q& operator <<(const char* x) { while (*x) w(*x++); return *this; }template<typename t> q& operator<< (t x) { if (!x) w(48); else if (x < 0) for (w(45); x; x /= 10) *p++ = 48 | -(x % 10); else for (; x; x /= 10) *p++ = 48 | x % 10; while (p != h) w(*--p); return *this; } }qio; }using nqio::qio;
using namespace std;
const int N = 2e5 + 10;
int n, m1, m2, primes[N], c;
map<int, int> fac;
vector<int> s;
void dec(int x) {
	int t = x;
	for (int i = 2; i <= x / i; ++i) {
		if (x % i) continue;
		while (x % i == 0) {
			++fac[i];
			x /= i;
		}
	}
	if (x > 1) ++fac[x];
}
void dfs(int x, int now) {
	if (x == c + 1) {
		s.emplace_back(now);
		return;
	}
	for (int i = 1, t = 1; i <= fac[primes[x]] + 1; ++i) {
		dfs(x + 1, now * t);
		t *= primes[x];
	}
}
void solve() {
	fac.clear(); s.clear();
	c = 0;
	cin >> n >> m1 >> m2;
	dec(m1), dec(m2);
	for (auto [x, y] : fac) {
		primes[++c] = x;
	}
	dfs(1, 1);
	sort(all(s));
	vector<int> f(s.size() + 1, 0);
	int ans1 = 0, ans2 = 0;
	for (int i = 0; i < s.size(); ++i) {
		int x = s[i];
		if (x <= n) {
			f[i] = x;
		}else {
			f[i] = 0;
			for (int j = 1; j <= c; ++j) {
				int p = primes[j], pre = lower_bound(all(s), x / p) - s.begin();
				if (x % p == 0 && f[pre] && x / f[pre] <= n) f[i] = max(f[i], f[pre]);
			}
		}
		if (f[i]) {
			++ans1, ans2 ^= (x / f[i]);
		}
	}
	cout << ans1 << " " << ans2 << "\n";
}
signed main() {
	IOS;
	int T;
	cin >> T;
	while (T--) solve();
}

F1.

题意:有n阶完全图,对图中的边进行红蓝染色,要求该图要么只是红联通,要么只是蓝联通,求合法的染色方案数,并且两种颜色都至少被用到一次.

引理:任何一个不联通图的补图都联通.证明:对于不联通图中的两个联通分量,补图会将这两个分量的每个点互相配对,形成一个联通块,归纳可得整个图都会联通.

所以所有合法方案可以分成两种情况,红不联通或者蓝不联通(即满足蓝不联通的前提下红联通).我们计算红不联通,即一个图的联通块数大于等于2的所有情况.设A[n]为n个节点的合法染色方案数,那么就包含了大于等于两个联通块的所有方案,和只有一个联通块的部分方案(合法方案,即蓝不联通).设B[n]为n个节点只有一个联通块的合法方案,枚举1号点所在的联通块大小(1~n-1),B[n] = ∑(k=1~n-1)C(n-1,k-1)B(k)*A(n-k),拿1号点联通块去链接其他点联通块,由于我们想要确保连边方案是唯一的,由上面的定义我们拿边去链接这两个联通块的所有点,这样两个联通块一定不会联通,所以形成的图一定是联通的,等于B[n].初始化A[1] = B[1] = 1, A[n] = 2 * B[n](n >= 2).最后得到A[n]为了满足题意,减去两种全蓝和全红的方案.

#include <bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0) 
#define ll long long 
// #define double long double
#define ull unsigned long long 
#define PII pair<int, int> 
#define PDI pair<double, int> 
#define PDD pair<double, double> 
#define debug(a) cout << #a << " = " << a << endl 
#define point(n) cout << fixed << setprecision(n)
#define all(x) (x).begin(), (x).end() 
#define mem(x, y) memset((x), (y), sizeof(x))
#define lbt(x) (x & (-x)) 
#define SZ(x) ((x).size()) 
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
// namespace nqio { const unsigned R = 4e5, W = 4e5; char* a, * b, i[R], o[W], * c = o, * d = o + W, h[40], * p = h, y; bool s; struct q { void r(char& x) { x = a == b && (b = (a = i) + fread(i, 1, R, stdin), a == b) ? -1 : *a++; } void f() { fwrite(o, 1, c - o, stdout); c = o; } ~q() { f(); }void w(char x) { *c = x; if (++c == d) f(); } q& operator >>(char& x) { do r(x); while (x <= 32); return *this; } q& operator >>(char* x) { do r(*x); while (*x <= 32); while (*x > 32) r(*++x); *x = 0; return *this; } template<typename t> q& operator>>(t& x) { for (r(y), s = 0; !isdigit(y); r(y)) s |= y == 45; if (s) for (x = 0; isdigit(y); r(y)) x = x * 10 - (y ^ 48); else for (x = 0; isdigit(y); r(y)) x = x * 10 + (y ^ 48); return *this; } q& operator <<(char x) { w(x); return *this; }q& operator<< (char* x) { while (*x) w(*x++); return *this; }q& operator <<(const char* x) { while (*x) w(*x++); return *this; }template<typename t> q& operator<< (t x) { if (!x) w(48); else if (x < 0) for (w(45); x; x /= 10) *p++ = 48 | -(x % 10); else for (; x; x /= 10) *p++ = 48 | x % 10; while (p != h) w(*--p); return *this; } }qio; }using nqio::qio;
using namespace std;
const int N = 2e5 + 10, mod = 998244353;
int B[N];
int fact[N], infact[N], inv[N];
void init (int n) {
    fact[0] = infact[0] = inv[0] = inv[1] = 1;
    for (int i = 2; i <= n; ++ i) 
        inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
    for (int i = 1; i <= n; ++ i) {
        fact[i] = 1ll * fact[i - 1] * i % mod;
        infact[i] = 1ll * infact[i - 1] * inv[i] % mod;
    }
}

int C(int n, int m) {
    if(n < m) return 0;
    if(m == 0 || n == m) return 1;
    return 1ll * fact[n] * infact[m] % mod * infact[n - m] % mod;
}
int dfs(int n) {
	if (B[n] != -1) {
		return B[n];
	}
	if (n <= 2) {
		return B[n] = 1;
	}
	int res = 0;
	for (int k = 1; k <= n - 1; ++k) {
		(res += dfs(n - k) * dfs(k) % mod * C(n - 1, k - 1) % mod * 2 % mod * (k == n - 1 ? (mod + 1) / 2 : 1) % mod) %= mod;	
	}
	return B[n] = res;
}
void solve() {
	int n;
	cin >> n;
	cout << 2 * (dfs(n) - 1) % mod << "\n";
}
signed main() {
	IOS;
	init(N - 10);
	mem(B, -1);
	int T = 1;
	// cin >> T;
	while (T--) solve();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值