CodeChef January Challenge 2020 Division 2 题解

( exttt{A})

爆搜。

#include <bits/stdc++.h>

#pragma GCC optimize(2)

using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi; 

int gi() {
	int f = 1, x = 0; 
	char ch = getchar();
	while (ch < '0' || ch > '9') { 
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + ch - '0';
		ch = getchar();
	}
	return f * x; 
}

int w1, w2, w3, s, step = 0x3f3f3f3f;

void dfs(vi v, bool last_swap, int now_step) {
	if (! v.size()) {
		step = min(step, now_step);
		return; 
	}
	if (!last_swap) {
		vi cp = v;
		reverse(cp.begin(), cp.end()); 
		dfs(cp, 1, now_step);
	}
	
	int sum = v[0];
	if (sum > s) return; 
	for (int i = 1; i < v.size(); i++) {
		if (sum + v[i] <= s) sum += v[i];
		else {
			vi t; 
			for (int j = i; j < v.size(); j++) t.push_back(v[j]);
			dfs (t, 0, now_step + 1); 
			return; 
		}
	}
	if (sum <= s) {
		dfs(vector<int>(), 0, now_step + 1);  
	}
}
int main() {
	int t = gi();
	while (t--) {
		s = gi(), w1 = gi(), w2 = gi(), w3 = gi();
		step = 0x3f3f3f3f;
		vector <int> v;
		v.push_back(w1);
		v.push_back(w2);
		v.push_back(w3);
		dfs (v, 0, 0); 
		cout << step << endl; 
	}
	return 0; 
}

( exttt{B})

本方(force)一下两方说的数之和(=10^x)即可。

#include <bits/stdc++.h>

#pragma GCC optimize(2)

using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;

ll gi() {
	ll f = 1, x = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + ch - '0';
		ch = getchar();
	}
	return f * x;
}

int t;
ll n, a, b, c, d, e; 
ll Pow(ll x, ll y) {
	ll res = 1;
	while (y) {
		if (y & 1) res = res * x;
		x = x * x;
		y >>= 1;
	} 
	return res; 
}
int main() {
	t = gi();
	while (t--) {
		n = gi();
		a = gi();
		ll ans = Pow(10, n) * 2 + a;
		cout << ans << endl;
		b = gi();
		cout << Pow(10, n) - b << endl;
		d = gi();
		cout << Pow(10, n) - d << endl;
		int correct_answer;
		cin >> correct_answer; 
		assert(correct_answer == 1); 
	}

  return 0;
}

( exttt{C})

直接二分哈希找最长index回文串,模板题。

#include <bits/stdc++.h>

#pragma GCC optimize(2)
#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)
using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;
typedef unsigned long long ull; 

int gi() {
	int f = 1, x = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + ch - '0';
		ch = getchar();
	}
	return f * x;
}

const int N = 111111; 
const ull bas = 10002059; 
int t, n, m;
ull pw[N]; 
int main() {
	t = gi();
	while (t--) {
		n = gi(), m = gi();
		vector <vi> v(n + 2);
		rep (i, 0, n) v[i].resize(m + 2); 
		vector <vector <ull> > hash_row(n + 2), rhash_row(n + 2);
		rep (i, 0, n + 1) hash_row[i].resize(m + 2), rhash_row[i].resize(m + 2);
		vector <vector <ull> > hash_col(n + 2), rhash_col(n + 2); 
		rep (i, 0, n + 1) hash_col[i].resize(m + 2), rhash_col[i].resize(m + 2); 
		const int L = max(n, m); 
		pw[0] = 1;
		rep (i, 1, L) pw[i] = pw[i - 1] * 10002059; 
		rep (i, 1, n) 
			rep (j, 1, m)
				v[i][j] = gi();
		rep (i, 1, n) {
			rep (j, 1, m) hash_row[i][j] = hash_row[i][j - 1] * bas + v[i][j];
			per (j, m, 1) rhash_row[i][j] = rhash_row[i][j + 1] * bas + v[i][j]; 
		}
		rep (j, 1, m) {
			rep (i, 1, n) hash_col[i][j] = hash_col[i - 1][j] * bas + v[i][j];
			per (i, n, 1) rhash_col[i][j] = rhash_col[i + 1][j] * bas + v[i][j]; 
		}
		auto Hash_row = [&](int nn, int l, int r) {return hash_row[nn][r] - hash_row[nn][l - 1] * pw[r - l + 1];};
		auto RHash_row = [&](int nn, int l, int r) {return rhash_row[nn][l] - rhash_row[nn][r + 1] * pw[r - l + 1];};
		auto Hash_col = [&](int mm, int l, int r) {return hash_col[r][mm] - hash_col[l - 1][mm] * pw[r - l + 1];};
		auto RHash_col = [&](int mm, int l, int r) {return rhash_col[l][mm] - rhash_col[r + 1][mm] * pw[r - l + 1];};
		ll ans = 0; 
		rep (i, 1, n) 
			rep (j, 1, m) {
				int l = 1, r = min(j, m - j + 1), ans1 = 1, ans2 = 1;
				while (l <= r) {
					int mid = (l + r) >> 1;
					if (Hash_row(i, j - mid + 1, j) == RHash_row(i, j, j + mid - 1))
						ans1 = mid, l = mid + 1;
					else r = mid - 1;
				}
				l = 1, r = min(i, n - i + 1);
				while (l <= r) {
					int mid = (l + r) >> 1;
					if (Hash_col(j, i - mid + 1, i) == RHash_col(j, i, i + mid - 1))
						ans2 = mid , l = mid + 1;
					else r = mid - 1;
				}
				ans += min(ans1, ans2); 
			}
		cout << ans << endl; 
	}
  return 0;
}

( exttt{D})

进行一步转化,维护相邻两个数的关系而非维护数。

这样就是问区间有多少个极长的指定字符段了,线段树维护。

#include <bits/stdc++.h>

#pragma GCC optimize(2)

#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)
using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;

int gi() {
	int f = 1, x = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + ch - '0';
		ch = getchar();
	}
	return f * x;
}

const int N = 111111;
int n, q, a[N];
char op[N]; 
struct seg {
	int sumdec, suminc;
	seg() { sumdec = suminc = 0; }
}t[N << 2];

void build(int p, int l, int r) {
	if (l == r) {
		if (op[l] == '>') t[p].sumdec = 1;
		else t[p].suminc = 1;
		return; 
	}
	int mid = (l + r) >> 1;
	build((p * 2), l, mid);
	build((p * 2 + 1), mid + 1, r);
	t[p].sumdec = t[p * 2].sumdec + t[p * 2 + 1].sumdec - (op[mid] == '>' && op[mid + 1] == '>');
	t[p].suminc = t[p * 2].suminc + t[p * 2 + 1].suminc - (op[mid] == '<' && op[mid + 1] == '<');
}

int querydec(int p, int L, int R, int l, int r) {
	if (L <= l && r <= R) return t[p].sumdec;
	int mid = (l + r) >> 1;
	if (L > mid) return querydec(p * 2 + 1, L, R, mid + 1, r);
	else if (R <= mid) return querydec(p * 2, L, R, l, mid);
	else return querydec(p * 2, L, R, l, mid) + querydec(p * 2 + 1, L, R, mid + 1, r) - (op[mid] == '>' && op[mid + 1] == '>');
}

int queryinc(int p, int L, int R, int l, int r) {
	if (L <= l && r <= R) return t[p].suminc;
	int mid = (l + r) >> 1;
	if (L > mid) return queryinc(p * 2 + 1, L, R, mid + 1, r);
	else if (R <= mid) return queryinc(p * 2, L, R, l, mid);
	else return queryinc(p * 2, L, R, l, mid) + queryinc(p * 2 + 1, L, R, mid + 1, r) - (op[mid] == '<' && op[mid + 1] == '<');
}
int main() {
	n = gi(), q = gi();
	rep (i, 1, n) a[i] = gi();
	rep (i, 2, n) op[i] = (a[i - 1] < a[i]) ? '<' : '>';
	
	build(1, 2, n);
	
	while (q--) {
		int l = gi() , r = gi();
		int sum = querydec(1, l + 1, r, 2, n), sum1 = queryinc(1, l + 1, r, 2, n);
		puts(sum == sum1 ? "YES": "NO"); 
	}
  return 0;
}

( exttt{E})

不会,听同学讲了一遍会了。

注意到给了这些数,我们是可以算出来如果这个数列合理,所有数的和的。因为可以前缀后缀和一一配对。

那么接下来进行一波无解的特判之后就可以考虑进行一个类似于往前缀和后缀和数组里填数一样的操作。大概就是选个位置然后乘个二的幂,实际意义也很显然。

#include <bits/stdc++.h>

#pragma GCC optimize(2)

#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)
using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;

int gi() {
	int f = 1, x = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + ch - '0';
		ch = getchar();
	}
	return f * x;
}

const int N = 262144, mod = (int)1e9 + 7; 
int T, n, x[N]; 
int fac[N], ifac[N];
int C(int n, int m){
	return 1ll * fac[n] * ifac[n - m] % mod * ifac[m] % mod; 
}

int qpow(int a, int b) {
	if (!b) return 1;
	int res = qpow(a, b >> 1);
	res = 1ll * res * res % mod;
	return (b & 1) ? 1ll * res * a % mod: res;  
}
unordered_map <int, int> po;
int main() {
	freopen("in.in", "r", stdin);
	T = gi();
	while (T--) {
		po.clear();
		n = gi();
		vi v; 
		ll sum = 0; 
		rep (i, 1, n << 1) {
			x[i] = gi();
			sum += x[i];
			if (!po[x[i]])
				v.push_back(x[i]); 
			++po[x[i]];
		}
		
		fac[0] = 1;
		rep (i, 1, n) fac[i] = 1ll * fac[i - 1] * i % mod;
		ifac[n] = qpow(fac[n], mod - 2);
		per (i, n - 1, 0) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod; 
		sum /= (n + 1); 
		sort(v.begin(), v.end());
		
		if (count(x + 1, x + (n << 1) + 1, sum) < 2) {
			puts("0");
			continue; 
		}
		
		int nowsz = n-1, flag = 0, ans = 1;
		po[sum] -= 2; 
		for (int i = 0; i < v.size(); i++) {
			int tot = sum - v[i];
			if (v[i] > tot) break;
			else if (v[i] < tot) {
				if (po[v[i]] != po[tot]) {
					flag = 1;
					break;
				}
				else ans = 1ll * ans * C(nowsz, po[v[i]]) % mod * qpow(2, po[v[i]]) % mod, nowsz -= po[v[i]];
			}
			else {
				if (po[v[i]] % 2) {
					flag = 1;
					break;
				}
				else {
					int hf = po[v[i]] / 2;
				//	ans = 1ll * ans * ;
					nowsz -= hf; 
					break; 
				}
			}
		}
		if (flag == 1 || nowsz) puts("0");
		else printf("%d
", ans); 
	}
  return 0;
}

( exttt{F})

还是不会,看了题解会的。

考虑如果放宽条件,改成LCP长度的平方怎么做。

考虑用Trie来贪心。每次尽可能尝试着匹配当前的深度,再将剩下的往上传给父亲。

min(LCP,LCS)就要用到很重要的一步转化。

例如"abc"这个串,我们构造出"acbbca"

min(LCP,LCS)2就等于(LCP/2)2

就可以用刚刚那个方法过了

#include <bits/stdc++.h>

#pragma GCC optimize(2)

#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)
using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;

int gi() {
	int f = 1, x = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + ch - '0';
		ch = getchar();
	}
	return f * x;
}

const int N = 200010;
struct trie {
	int sum;
	int ch[26];
}t[N];

int cnt = 0, len, root; 
ll ans = 0; 
ll sqr(int x) {return 1ll * x * x;}
char c[N], cc[N];
void Reset() {while (cnt) memset(t[cnt].ch, 0, sizeof(t[cnt].ch)), t[cnt].sum = 0, --cnt;}
void Insert(int& now, int p) {
	if (!now) now = ++cnt;
	t[now].sum++; 
	if (p == len * 2 + 1) return; 
	Insert(t[now].ch[c[p] - 'a'], p + 1);
}
int match(int now, int dep) {
	if (!now) return 0;
	int lf = t[now].sum, tot = 0;  
	for (int i = 0; i < 26; i++) {
		int val = match(t[now].ch[i], dep + 1); 
		lf -= val;
		tot += val; 
	}
	int pairs = (lf >> 1);
	ans += pairs * sqr(dep / 2); 
	return tot + pairs * 2; 
}

void solve() {
	int n = gi();
	Reset();
	root = 0; 
	ans = 0; 
	rep (i, 1, n) {
		scanf("%s", cc + 1);
		len = strlen(cc + 1);
		int pos = 0; 
		rep (i, 1, len) c[++pos] = cc[i], c[++pos] = cc[len - i + 1];
		Insert(root, 1);
	}
	match(root, 0);
	
	printf("%lld
", ans); 
}
int main() {
	int tests = gi();
	while (tests--) solve();
  return 0;
}
原文地址:https://www.cnblogs.com/LiM-817/p/12198491.html