VP Educational Codeforces Round 14


A. Fashion in Berland

题意:有n个数,需要满足正好有n10或者n=1时正好一个1

记录1的个数,判断即可。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    int cnt = std::count(a.begin(), a.end(), 1);
    if ((n == 1 && cnt == 1) || (n > 1 && cnt == n - 1)) {
    	std::cout << "YES\n";
    } else {
    	std::cout << "NO\n";
    }
}

B. s-palindrome

题意:判断一个字符串是不是镜像的,所谓镜像就是对应字母是对称的。

需要一点点耐心找对称的字母。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    std::map<char, char> mp;
    std::vector<std::string> ss{"AA", "bd", "HH", "II", "MM", "OO", "oo", "YY", "XX", 
    "xx", "pq", "TT", "UU", "vv", "VV", "WW", "ww"};
    for (auto & t : ss) {
    	mp[t[0]] = t[1];
    	mp[t[1]] = t[0];
    }

    int n = s.size();
    for (int l = 0, r = n - 1; l <= r; ++ l, -- r) {
    	if (mp[s[l]] != s[r]) {
    		std::cout << "NIE\n";
    		return;
    	}
    }

    std::cout << "TAK\n";
}

C. Exponential notation

题意:给你一个大数,把它转换为科学计数法表示。

模拟题,需要一点细节。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    int l = -1, r = -1;
    for (int i = 0; i < n; ++ i) {
    	if (s[i] != '0' && s[i] != '.') {
    		l = i;
    		break;
    	}
    }

    for (int i = n - 1; i >= 0; -- i) {
    	if (s[i] != '0' && s[i] != '.') {
    		r = i;
    		break;
    	}
    }

    int p = s.find('.');
    if (p == s.npos) {
    	p = n;
    }

    if (l == -1) {
    	std::cout << 0 << "\n";
    	return;
    } 

    std::string ans;
    ans += s[l];
    if (l < r) {
    	ans += '.';
    }

    for (int i = l + 1; i <= r; ++ i) {
    	if (s[i] != '.') {
    		ans += s[i];
    	}
    }	

    if (l + 1 != p) {
    	ans += "E";
    	if (l < p) {
    		ans += std::to_string(p - l - 1);
    	} else {
    		ans += std::to_string(p - l);
    	}
    }
    std::cout << ans << "\n";
}

D. Swaps in Permutation

题意:给你一个数组,以及m个可以交换的位置,求数组操作后的最大字典序。

根据冒泡排序,对于每个可以交换的联通块,我们都可以让它降序排序。那么用并查集维护联通块,每个联通块单独排序。

点击查看代码
struct DSU {
	std::vector<int> fa, cnt;
	DSU(int _n) {
		init(_n);
	}

	void init(int _n) {
		fa.assign(_n, 0);
		cnt.assign(_n, 1);
		std::iota(fa.begin(), fa.end(), 0);
	}

	int find(int x) {
		return x == fa[x] ? x : fa[x] = find(fa[x]);
	}

	bool merge(int x, int y) {
		x = find(x), y = find(y);
		if (x == y) {
			return false;
		}

		fa[y] = x;
		cnt[x] += cnt[y];
		return true;
	}

	bool same(int x, int y) {
		return find(x) == find(y);
	}

	int size(int x) {
		return cnt[find(x)];
	}
};

void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

  	DSU dsu(n);
  	for (int i = 0; i < m; ++ i) {
  		int u, v;
  		std::cin >> u >> v;
  		-- u, -- v;
  		dsu.merge(u, v);
  	}

  	std::vector<std::vector<int>> g(n);
  	for (int i = 0; i < n; ++ i) {
  		g[dsu.find(i)].push_back(i);
  	}

  	for (int i = 0; i < n; ++ i) {
  		std::vector<int> b;
  		for (auto & x : g[i]) {
  			b.push_back(a[x]);
  		}

  		std::sort(b.begin(), b.end(), std::greater<int>());
  		for (int j = 0; j < b.size(); ++ j) {
  			a[g[i][j]] = b[j];
  		}
  	}

  	for (int i = 0; i < n; ++ i) {
  		std::cout << a[i] << " \n"[i == n - 1];
  	}
}

E. Xor-sequences

题意:给你n个数,如果两个数异或后二进制下1的个数是3的倍数,这两个就可以在序列中相邻。求有多少种长度为k的序列。

如果我们建立一个邻接矩阵,那么g[i][j]表示j能否在i后面,那么问题转换为求一个图中节点个数为k的路径有多少,变成了矩阵乘法板子。

点击查看代码
const int N = 100;
using M = std::array<std::array<Z, N>, N>;

int n;
i64 k;

struct Mat {
	M mat;

	Mat() {
		init();
	}

	void init() {
		for (int i = 0; i < n; ++ i) {
			for (int j = 0; j < n; ++ j) {
				mat[i][j] = 0;
			}
		}
	}

	std::array<Z, N> & operator [](const int i) {
		return mat[i];
	}
};

Mat operator * (Mat & a, Mat & b) {
	static Mat c;
	for (int i = 0; i < n; ++ i) {
		for (int j = 0; j < n; ++ j) {
			c[i][j] = 0;
			for (int k = 0; k < n; ++ k) {
				c[i][j] += a[i][k] * b[k][j];
			}
		}
	}

	return c;
}

void solve() {
	std::cin >> n >> k;
    std::vector<i64> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    auto count = [&](i64 x) -> int {
    	int res = 0;
    	while (x) {
    		if (x & 1) {
    			++ res;
    		}

    		x >>= 1;
    	}

    	return res;
    };

    Mat g;
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < n; ++ j) {
    		if (count(a[i] ^ a[j]) % 3 == 0) {
    			g[i][j] = 1;
    		}
    	}
    }

    Mat res;
    for (int i = 0; i < n; ++ i) {
    	res[i][i] = 1;
    }

    -- k;
    while (k) {
    	if (k & 1) {
    		res = res * g;
    	}

    	g = g * g;
    	k >>= 1;
    }

    Z ans = 0;
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < n; ++ j) {
    		ans += res[i][j];
    	}
    }

    std::cout << ans << "\n";
}

F. Couple Cover

题意:对于每个p,求a中有多少i,j满足a[i]×a[j]>=p

发现值域只有3e6,考虑预处理,可以记录每个数出现的个数,然后枚举每个数的倍数,那么我们记f[k] = a[i]×a[j]==k的个数,那么a[i]×a[j]<k的个数就是i=1k1f[k]。 总个数有n(n1)2个,那么对于每个p,答案就是n(n1)2i=1p1f[p]

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    const int N = 3e6 + 5;
    std::vector<int> cnt(N);
    for (int i = 0; i < n; ++ i) {
    	int x;
    	std::cin >> x;
    	++ cnt[x];
    }

    std::vector<i64> f(N);
    for (int i = 1; i < N; ++ i) {
    	for (int j = i; j < N; j += i) {
    		f[j] += (i64)cnt[i] * (cnt[j / i] - (i == j / i));
    	}
    }

    for (int i = 1; i < N; ++ i) {
    	f[i] += f[i - 1];
    }

    int m;
    std::cin >> m;
    while (m -- ) {
    	int x;
    	std::cin >> x;
    	std::cout << (i64)n * (n - 1) - f[x - 1] << "\n";
    }
}
posted @   maburb  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示