Codeforces Round #383 (Div. 2)
Codeforces Round #383 (Div. 2)#
A. Arpa’s hard exam and Mehrdad’s naive cheat##
题意:
求1378n的末位数字(0<=n<=109)。
分析:
小学数学题。时间复杂度为O(1)。
代码如下:
#include <cstdio>
#include <cstring>
int main() {
//freopen("input.txt", "r", stdin);
int n;
while (~scanf("%d", &n)) {
if (n == 0) printf("1\n");
else {
int buf = n % 4;
switch (buf) {
case 0: puts("6"); break;
case 1: puts("8"); break;
case 2: puts("4"); break;
case 3: puts("2"); break;
}
}
}
return 0;
}
B. Arpa’s obvious problem and Mehrdad’s terrible solution##
题意:
定义一种运算,实际上就为位运算中的按位异或。给出n(1<=n<=105)个数(1<=ai<=105),给出x(0<=x<=10^5)。求有多少对ai和aj按位异或等于x。
分析:
由于ai的范围不大,可用数组记录ai出现的次数,对每个ai,ai^x即等于要找的aj,再统计求和即可。注意x=0的情况,因为没考虑到这点虽比赛中过了,但比赛结束后system test被刷下来了。时间复杂度为O(10^5)。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 3;
int cnt[maxn], n, x;
inline void read(int& buf) {
buf = 0;
char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) {
buf = (buf << 3) + (buf << 1) + (c - '0'); c = getchar();
}
}
int main() {
//freopen("input.txt", "r", stdin);
while (~scanf("%d", &n)) {
scanf("%d", &x);
memset(cnt, 0, sizeof(cnt));
int min_val = 0x7fffffff, max_val = 0;
for (int i = 1; i <= n; i++) {
int buf; read(buf);
cnt[buf] += 1;
min_val = min(min_val, buf);
max_val = max(max_val, buf);
}
ll ans = 0LL;
for (int i = min_val; i <= max_val; i++) {
if (!cnt[i]) continue;
int need = x ^ i;
if (need < min_val || need > max_val) continue;
if (cnt[need]) {
if (!x) ans += ll(cnt[i]) * ll(cnt[need] - 1);
else ans += ll(cnt[i]) * ll(cnt[need]);
}
}
printf("%I64d\n", ll(ans >> 1));
}
return 0;
}
C. Arpa's loud Owf and Mehrdad's evil plan##
题意:
有n(1<=n<=100)个人,编号1到n,每个人有一个数字crush_i(1<=crush_i<=n),有一个游戏规则如下,假设从编号为x的人开始一轮游戏,他对着编号为crush_x的人喊:“Owww...wwf。”(w重复t次),如果t大于1的话,编号为crush_x的人对着编号为crush_crush_x的人喊:“Owwww...wwwf。”(w重复t-1次)。这样一直持续下去,直到有个人收到“Owf”(w只重复1次),那么这个人就是这一轮游戏的Joon-Joon。要求解最小的t(t大于等于1),使得对于每个人x,他的Joon-Joon为y的话,那么y的Joon-Joon也为x。如果找不到这样的t,就输出-1。注意:可以自己朝自己喊话。
分析:
将每个人作为一个节点,x朝y喊话的话,就连一条从x到y的有向边,若存在点的入度为0则无解,输出-1,有解的话则表示图由若干个简单环构成,找出每个简单环的长度,并准备一个备选长度的集合,若这个长度为奇数,则直接添入备选集合,若这个长度为偶数,则除以2(题目要求最小的t,且除以2后也满足条件,则相对原数更优)后添入备选集合,最终的答案就是备选集合中所有数的最小公倍数。
时间复杂度为O(nlogn)。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 100 + 3;
int G[maxn];
int in_degree[maxn], n;
vector<int> len;
bool already[maxn];
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
int lcm(int a, int b) {
return a * b / gcd(a, b);
}
void dfs(int st, int now, int step) {
already[now] = true;
if (now == st) (step & 1) ? len.push_back(step) : len.push_back(step >> 1);
else dfs(st, G[now], step + 1);
}
int solve() {
len.clear();
memset(already, 0, sizeof(already));
for (int i = 1; i <= n; i++)
if (!already[i]) {
already[i] = true;
dfs(i, G[i], 1);
}
if (len.size() == 1) return len[0];
int buf = lcm(len[0], len[1]);
for (int i = 2; i < len.size(); i++) buf = lcm(buf, len[i]);
return buf;
}
int main() {
//freopen("input.txt", "r", stdin);
while (~scanf("%d", &n)) {
for (int i = 1; i <= n; i++) {
G[i] = -1; in_degree[i] = 0;
}
for (int i = 1; i <= n; i++) {
int to; scanf("%d", &G[i]);
in_degree[G[i]] += 1;
}
bool ok = true;
for (int i = 1; i <= n; i++)
if (!in_degree[i]) { ok = false; break; }
ok ? printf("%d\n", solve()) : puts("-1");
}
return 0;
}
D. Arpa's weak amphitheater and Mehrdad's valuable Hoses##
题意:
一共有n(1<=n<=1000)个hos,每个hos有对应的重量(1<=wi<=1000)和颜值(1<=bi<=10^6),其中有m(0<=m<=min(n*(n-1)/2, 10^5))对朋友,朋友关系具有传递性,现打算邀请其中的一些hos来参加party,对于同一只友谊的小船上的hos,如果打算邀请他们的话,要么只邀请一个hos,要么这艘船上所有的hos都要邀请,但是party上的重量总和w(1<=w<=1000)有限,保证邀请的hos的重量之和不超过w的前提下,使得他们的颜值的总和尽量大。求这个最优的颜值总和的数值。
分析:
连通块+背包dp。每个hos看作一个节点,朋友关系表示连以边,构图,找出每个连通块的重量总和和颜值总和作为物品,再将每个hos也作为一个物品,但要么加入连通块物品,不再加入连通块中的hos,要么不加入连通块物品,加入连通块中的其中一个hos,要么两者都不加入,即变成有三种选择的01-背包,时间复杂度为O(n*w)。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1000 + 3;
int n, m, w_bound, w[maxn], b[maxn], color[maxn];
vector<int> G[maxn];
vector<int> dp_b, dp_w;
int dp[maxn], group_size[maxn], group_cnt;
inline void read(int& buf) {
buf = 0;
char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) {
buf = (buf << 3) + (buf << 1) + (c - '0');
c = getchar();
}
}
int sum_bi, sum_wi;
void dfs(int idx, int to_be) {
color[idx] = to_be;
sum_bi += b[idx];
sum_wi += w[idx];
group_size[to_be] += 1;
dp_b.push_back(b[idx]);
dp_w.push_back(w[idx]);
int bound = G[idx].size();
for (int i = 0; i < bound; i++) {
int to = G[idx][i];
if (!color[to]) dfs(to, to_be);
}
}
void pre_dp() {
dp_b.clear(); dp_w.clear();
memset(color, 0, sizeof(color));
memset(group_size, 0, sizeof(group_size));
group_cnt = 0;
for (int i = 1; i <= n; i++) {
if (!color[i]) {
sum_bi = sum_wi = 0;
dfs(i, ++group_cnt);
dp_w.push_back(sum_wi); dp_b.push_back(sum_bi);
group_size[group_cnt] += 1;
}
}
//int bound = dp_w.size();
//for (int i = 0; i < bound; i++) {
// printf("%d %d\n", dp_w[i], dp_b[i]);
//}
}
void solve() {
//printf("group_cnt is %d\n", group_cnt);
for (int i = 0; i <= w_bound; i++) dp[i] = 0;
int idx = 0;
for (int i = 1; i <= group_cnt; i++) {
for (int j = w_bound; j >= 0; j--)
for (int k = 0; k < group_size[i]; k++)
if (j >= dp_w[idx + k])
dp[j] = max(dp[j], dp[j - dp_w[idx + k]] + dp_b[idx + k]);
idx += group_size[i];
//printf("group_size is %d\n", group_size[i]);
}
}
int main() {
//freopen("input.txt", "r", stdin);
while (~scanf("%d", &n)) {
read(m); read(w_bound);
for (int i = 1; i <= n; i++) G[i].clear();
for (int i = 1; i <= n; i++) read(w[i]);
for (int i = 1; i <= n; i++) read(b[i]);
while (m--) {
int x, y;
read(x); read(y);
G[x].push_back(y); G[y].push_back(x);
}
pre_dp(); solve();
printf("%d\n", dp[w_bound]);
}
return 0;
}