2025牛客寒假算法基础集训营3


A. 智乃的博弈游戏

题意:两个人轮流拿石头,拿的数量必须和总数互质,轮到某个玩家时只剩下一颗石头就算他赢。问先手能不能赢。

如果n>1并且是奇数可以拿走n2个,这样可以看出来奇数必赢。如果是偶数,那么我们只能拿一个奇数,偶数减奇数等于奇数,后手必赢。

点击查看代码
void solve() {
	i64 n;
	std::cin >> n;
	if (n & 1) {
		std::cout << "Yes\n";
	} else {
		std::cout << "No\n";
	}
}

B. 智乃的质数手串

题意:n个数,首尾相接。你每次可以选择两个相邻的数,如果它们的和是质数,那么可以删除前面那个数。如果只有一个数了可以直接删除。求一种方案删除所有数。

考虑不是环而是一条链该怎么做。从左到右看,如果有个数可以删那就直接删,不删的话也不能让它删去右边的数,留着反而没用。那么可以用一个栈来模拟,贪心的删除每个数。
考虑是环该怎么做。经典的破环成链,把数组复制一份到后面,然后用双端队列操作,每次把和当前位置距离已经超过n的位置出队,保证队列里存的每个位置都是当前可以操作的。那么当某个时刻队列为空,就找到了以当前元素结尾的一个合法数组。

点击查看代码
const int N = 2e5 + 5;

std::vector<int> primes;
bool st[N];

void init(int n) {
	for (int i = 2; i <= n; ++ i) {
		if (!st[i]) {
			primes.push_back(i);
		}

		for (auto & p : primes) {
			if (p * i > n) {
				break;
			}

			st[p * i] = true;
			if (i % p == 0) {
				break;
			}
		}
	}
}

void solve() {
	init(2e5);
	int n;
	std::cin >> n;
	std::vector<int> a(2 * n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
		a[i + n] = a[i];
	}

	std::deque<int> dq;
	int pos = -1;
	for (int i = 0; i < 2 * n; ++ i) {
		while (dq.size() && i - dq.front() >= n) {
			dq.pop_front();
		}

		while (dq.size() && !st[a[i] + a[dq.back()]]) {
			dq.pop_back();
		}

		if (i >= n - 1 && dq.empty()) {
			pos = i - n + 1;
			break;
		}

		dq.push_back(i);
	}

	if (pos == -1) {
		std::cout << "No\n";
	} else {
		std::cout << "Yes\n";
		std::vector<int> ans;
		std::stack<int> stk;
		for (int i = pos; i < pos + n; ++ i) {
			while (stk.size() && !st[a[i] + a[stk.top()]]) {
				ans.push_back(stk.top());
				stk.pop();
			}

			stk.push(i);
		}

		ans.push_back(stk.top());
		for (int i = 0; i < n; ++ i) {
			std::cout << ans[i] % n << " \n"[i == n - 1];
		}
	}
}

C. 智乃的Notepad(Easy version) && D. 智乃的Notepad(Hard version)

题意:你要输入n个字符串,你除了输入26个字母之外还可以退格。问至少敲多少次键盘可以让n个字符串都出现过。

显然我们应该让尽可能多的字符串共用前缀。模拟一棵字典树,可以发现我们按照字典树的dfs序走就是一种方案,发现哪个方案走到次数都一样,但最后一个字符串可以不删,那就相当于我们最后要停在字典树最深的一个分支上,这样答案就是2×字典树的总节点数减最大深度。其中最大深度就是最长的字符串长度,可以用st求出区间的最大长度,考虑怎么求区间的字典树总节点数。每个字符串插入的时候会经过一些点,我们把每个字符串经过点的编号存下来,那么问题就变成了求区间每个字符串所有经过的点里有多少个不同的点。这个问题和HH的项链几乎一样,HH的项链是每个位置是一个数,求区间不同数的个数,这个题是每个位置有很多数,求区间不同数的个数,类似的求法,存每个数上一次出现的位置,用树状数组维护。

点击查看代码
template <class Info> 
struct ST {
	std::vector<std::vector<Info>> st;
	ST(std::vector<Info> a) {
		int n = a.size(), m = std::__lg(n) + 1;
		st.assign(n, std::vector<Info>(m));
		for (int i = 0; i < n; ++ i) {
			st[i][0] = a[i];
		}

		for (int j = 1; j < m; ++ j) {
			for (int i = 0; i + (1 << j - 1) < n; ++ i) {
				st[i][j] = st[i][j - 1] + st[i + (1 << j - 1)][j - 1];
			}
		}
	}

	Info query(int l, int r) {
		int lg = std::__lg(r - l + 1);
		return st[l][lg] + st[r - (1 << lg) + 1][lg];
	}
};

struct Info {
	int max;
};

Info operator + (Info a, Info b) {
	return {std::max(a.max, b.max)};
}

template <class T>
struct Fenwick {
    int n;
    std::vector<T> tr;

    Fenwick(int _n) {
        init(_n);
    }

    void init(int _n) {
        n = _n;
        tr.assign(_n + 1, T{});
    }

    void add(int x, const T &v) {
        for (int i = x; i <= n; i += i & -i) {
            tr[i] = tr[i] + v;
        }
    }

    T query(int x) {
        T res = 0;
        for (int i = x; i; i -= i & -i) {
            res = res + tr[i];
        }
        return res;
    }

    T sum(int l, int r) {
        return query(r) - query(l - 1);
    }
};

const int N = 1e6 + 5;
std::vector<std::vector<int>> g(N);
int last[N];

const int TrieN = 1e6 + 5;
int trie[TrieN][26];
struct Trie {
	int idx;
	Trie(int n) {
		idx = 0;
	}

	int newNode() {
		idx += 1;
		memset(trie[idx], 0, sizeof trie[idx]);
		return idx;
	}

	void insert(std::string s, int id) {
		int p = 0;
		for (auto & c : s) {
			int x = c - 'a';
			if (!trie[p][x]) {
				trie[p][x] = newNode();
			}

			p = trie[p][x];
			g[id].push_back(p);
		}
	}
};

void solve() {
    int n, m;
    std::cin >> n >> m;
    int sum = 0;
    std::vector<std::string> s(n + 1);
    std::vector<Info> len(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	std::cin >> s[i];
    	len[i].max = s[i].size();
    	sum += s[i].size();
    }

    ST<Info> st(len);
    Trie tr(sum);
    for (int i = 1; i <= n; ++ i) {
    	tr.insert(s[i], i);
    }

    std::vector<std::vector<std::pair<int, int>>> Q(n + 1);
    for (int i = 0; i < m; ++ i) {
    	int l, r;
    	std::cin >> l >> r;
    	Q[r].push_back({l, i});
    }

    Fenwick<int> tr1(n + 1);
    std::vector<int> ans(m);
    for (int i = 1; i <= n; ++ i) {
    	for (auto & j : g[i]) {
    		if (last[j]) {
    			tr1.add(last[j], -1);
    		}
    		tr1.add(i, 1);
    		last[j] = i;
    	}

    	for (auto & [j, id] : Q[i]) {
    		ans[id] = 2 * tr1.sum(j, i) - st.query(j, i).max;
    	}
    }

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

E.智乃的小球

题意:n个小球在一个轴上,每个球的速度都是固定的,方向是左或右。如果有两个小球碰撞就会交换方向。问发生k次碰撞的时候是在多少秒。

两个球碰撞后可以看作是互相穿过了对方。因为它们交换了方向,然后他们的位置又是相邻的,完全可以看作两个小球都往自己的方向前进了。
那么我们可以二分时间,看每个球能和多少球相撞。

点击查看代码
void solve() {
	int n, k;
	std::cin >> n >> k;
	std::vector<i64> a, b;
	for (int i = 0; i < n; ++ i) {
		i64 p, v;
		std::cin >> p >> v;
		if (v == 1) {
			a.push_back(p);
		} else {
			b.push_back(p);
		}
	}

	std::sort(a.begin(), a.end());
	std::sort(b.begin(), b.end());
	n = a.size();
	int m = b.size();

	auto check = [&](double t) -> i64 {
		i64 cnt = 0;
		for (int i = 0, l = 0, r = 0; i < n; ++ i) {
			while (l < m && b[l] < a[i]) {
				++ l;
			}

			r = std::max(l, r);
			while (r < m && b[r] <= a[i] + 2 * t) {
				++ r;
			}

			cnt += r - l;
		}

		return cnt;
	};

	double l = 1, r = 1e9;
	while (r - l > 1e-6) {
		double mid = (l + r) / 2;
		// std::cerr << mid << "\n";
		if (check(mid) >= k) {
			r = mid;
		} else {
			l = mid;
		}
	}

	std::cout << std::fixed << std::setprecision(12);

	if (check(r) < k) {
		std::cout << "No\n";
		return;
	}

	std::cout << "Yes\n";
	std::cout << r << "\n";
}

F. 智乃的捉迷藏

题意:有六个位置,三个人看着。其中每个人都有一个位置只能自己看到。其他三个位置都会被某两个人看到。总共有n个人在这六个位置里,选择告诉你每个人看见了多少人,问这个情况有没有可能。

在能被两个位置看到的人会被算多次。那么人数最少为所有人都不在会在能被两个人看见的位置上,那么就是a+b+c个人。最多的情况就是每个人都在能被两个位置看到的人的位置上,那么每个人会被算两次。就是2(a+b+c)。只要n在这个范围内就有解。

点击查看代码
void solve() {
	int n, a, b, c;
	std::cin >> n >> a >> b >> c;
	if (a + b + c < n || a + b + c > n * 2) {
		std::cout << "No\n";
	} else {
		std::cout << "Yes\n";
	}
}

G. 智乃与模数

题意:求所有的n%i(1in)的前k大和。

对于一个区间[l,r],都有i[l,r],nl=ni=nr,那么我们发现他们的n%i的值是一段等差数列,首项an%l,公差dnl,第i项为a(i1)d。(这种结论第一次遇到难以推出来,不过现在遇到了就一定要记下来)。
那么我们可以二分找前k大的数是哪些,每次遍历这些等差数列,看大于等于mid的数量是不是大于等于k。如果有k个了,那么我们的mid可以增大,否则减小。枚举每一个[l,r]可以用数论分块来做。
这题思路大致就是这样,不过二分还是有点小细节,可能没有一个mid使得大于等于mid的数恰好有k个,那么如果我们二分第一个个数小于等于kmid,那么可能我们统计的数不足k个,于是我们需要加上kcntmid1。其中cnt是大于等于mid的个数,一定有这么多个mid1,不然就会有大于等于mid1的数个数小于等于k个,与我们二分出来的答案矛盾。

点击查看代码
void solve() {
	i64 n, k;
	std::cin >> n >> k;

	auto check = [&](int x) -> std::pair<int, i64> {
		int cnt = 0;
		i64 sum = 0;
		for (int l = 1, r; l <= n; l = r + 1) {
			r = n / (n / l);
			int a = n % l, d = n / l;
			if (a < x) {
				continue;
			}
			//a - (i - 1) * d >= x
			//i <= (a - x) / d + 1
			i64 len = std::min(r - l + 1, (a - x) / d + 1);
			cnt += len;
			sum += len * (a + a - (len - 1) * d) / 2;
		}

		return {cnt, sum};
	};

	int l = 1, r = n / 2;
	while (l < r) {
		int mid = l + r >> 1;
		if (check(mid).first <= k) {
			r = mid;
		} else {
			l = mid + 1;
		}
	}

	auto [cnt, sum] = check(l);
	i64 ans = sum + (i64)(k - cnt) * (l - 1);
	std::cout << ans << "\n";
}

H. 智乃与黑白树

题意:给你一棵树,每个点要么是黑的要么是白的。问所有是黑色开头白色结尾的路径长度之和。

这题的讨论还是有点麻烦,出题人的写法很好,以前没见过,感觉让换根dp变的好理解了,这里借鉴一下。
fuu这颗子树的贡献,cntu0/1u这棵子树里0/1的数量,sumu0/1u这棵子树里黑色点/白色点到u的距离之和。
如果已经算出来了以u为根的一些子树的贡献,选择要把一棵子树v接到u上,那么每个u里的黑点都要去v的白点,白点要去v里的黑点,发现他们都要经过点u,那么我们把这些路径分成两部。以黑点举例,黑点到u的距离为sumu0,这些距离要算上cntv1遍,那么就是sumu0×cntv1。然后看从u到左边的白点要走多少,左边白点到v的距离已经有了,那么他们要到u只需要加1,因为每个白点都要算,所以距离为sumv1+cntv1,这个距离要算cntu0次。白点到黑点的计算同理。于是总的距离就是fu=fv+sumu0×cntv1+cntu0×(sumv1+cntv1)+sumu1×cntv0+cntu1×(sumv0+cntv0)
sumcnt的转移则好讨论。我们可以把这个写成一个函数linklink(u,v)表示把v接到u上这样我们换根的时候就更直观更好写。然后再写一个cut函数,撤销之前的link。那么换根操作中,我们就可以先用cutvu的贡献脱离出来,然后再link(v,u)u接到v上。

点击查看代码
void solve() {
	int n;
	std::cin >> n;
	std::string s;
	std::cin >> s;
	std::vector<std::vector<std::pair<int, int> > > adj(n);
	std::vector<std::pair<int, int> > edges(n);
	for (int i = 1; i < n; ++ i) {
		int u, v;
		std::cin >> u >> v;
		-- u, -- v;
		adj[u].push_back({i, v});
		adj[v].push_back({i, u});
		edges[i] = {u, v};
	}

	std::vector cnt(n, std::array<i64, 2>{});
	std::vector sum(n, std::array<i64, 2>{});
	std::vector<i64> f(n);

	auto link = [&](int u, int v) -> void {
		f[u] += f[v] + sum[u][0] * cnt[v][1] + sum[u][1] * cnt[v][0] + 
				cnt[u][0] * (sum[v][1] + cnt[v][1]) + cnt[u][1] * (sum[v][0] + cnt[v][0]);

		sum[u][0] += sum[v][0] + cnt[v][0];
		sum[u][1] += sum[v][1] + cnt[v][1];

		cnt[u][0] += cnt[v][0];
		cnt[u][1] += cnt[v][1];
	};

	auto cut = [&](int u, int v) -> void {
		cnt[u][1] -= cnt[v][1];
		cnt[u][0] -= cnt[v][0];

		sum[u][1] -= sum[v][1] + cnt[v][1];
		sum[u][0] -= sum[v][0] + cnt[v][0];

		f[u] -= f[v] + sum[u][0] * cnt[v][1] + sum[u][1] * cnt[v][0] + 
				cnt[u][0] * (sum[v][1] + cnt[v][1]) + cnt[u][1] * (sum[v][0] + cnt[v][0]);
	};

	auto dfs = [&](auto self, int u, int fa) -> void {
		int x = s[u] == 'b';
		cnt[u][x] = 1;
		for (auto & [_, v] : adj[u]) {
			if (v == fa) {
				continue;
			}

			self(self, v, u);
			link(u, v);
		}
	};

	dfs(dfs, 0, -1);

	std::vector<std::pair<i64, i64> > ans(n);
	auto dfs1 = [&](auto self, int u, int fa) -> void {
		for (auto & [id, v] : adj[u]) {
			if (v == fa) {
				continue;
			}

			cut(u, v);
			if (u == edges[id].first) {
				ans[id] = {f[u], f[v]};
			} else {
				ans[id] = {f[v], f[u]};
			}

			link(v, u);
			self(self, v, u);
			cut(v, u);
			link(u, v);
		}
	};

	dfs1(dfs1, 0, -1);
	for (int i = 1; i < n; ++ i) {
		std::cout << ans[i].first << " " << ans[i].second << "\n";
	}
}

I. 智乃的兔子跳

题意:给你n个数,你要选一个p和一个k,使得p+ik包含尽可能多的数,i是一个非负整数。

以前没有接触过这种随机数的题。
k=2的时候,我们可以选所有奇数或者偶数,至少可以选n2个点。那么答案可以选的点肯定也大于等于n2,所以一个点在答案里的概率大于12,两个点同时在一个答案里的概率大于14。那么我们可以多次随机两个点,枚举这两个点可能产生的k,如果这两个同时在答案里,那么我们就可以枚举到答案。我们枚举一百次,那么枚举不到答案的概率极小极小。

点击查看代码
std::mt19937 gen(std::random_device{}());

int rand(int l, int r) {
	std::uniform_int_distribution<int> dis(l, r);
	return dis(gen);
}

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

	if (n == 1) {
		std::cout << a[0] << " " << 2 << "\n";
		return;
	}

	auto get = [&](int p, int d) -> std::pair<int, int> {
		int cnt = 0;
		for (auto & x : a) {
			if ((x - p) % d == 0) {
				++ cnt;
			}
		}

		return {cnt, p % d};
	};

	int ans = 2;
	int p = 0, max = 0;

	int t = 100;
	while (t -- ) {
		int i = rand(0, n - 1), j;
		do {
			j = rand(0, n - 1);
		} while (i == j);

		int k = std::abs(a[i] - a[j]);
		if (k == 1) {
			continue;
		}

		for (int d = 2; d * d <= k; ++ d) {
			if (k % d == 0) {
				while (k % d == 0) {
					k /= d;
				}

				auto [cnt, pos] = get(a[i], d);
				if (cnt > max) {
					max = cnt;
					p = pos;
					ans = d;
				}
			}
		}

		if (k == 1) {
			continue;
		}

		auto [cnt, pos] = get(a[i], k);
		if (cnt > max) {
			max = cnt;
			p = pos;
			ans = k;
		}
	}

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

J. 智乃画二叉树

题意:按要求画一棵二叉树。
感觉这题对我来说并不算难,写过蓝书上的搜索章节题目后,对于这种题还是得心应手的。不过赛时没看这题。。。

先算出最大高度和宽度,都是三百八十几,那么我们开个400×400的字符数组就够了。先把所有字符都赋值为空格。如何dfs去画这棵树,根的位置可以取395200,这个位置是六边形左上角的位置。然后左右节点的坐标就可以直接算出来,直接dfs就行。现在考虑画边,就是分别从六边形的左下角和右下角出发,一直斜着往下直到儿子的高度就行了。最后的边框就是找到不等于空格的位置的坐标的最高最低最左最右的线就行了。

点击查看代码
const int N = 400;

char a[N][N];
int son[100][2];
int in[100];
int len[10];

void draw_node(int h, int w, int u) {
	a[h][w] = a[h][w + 1] = '_';
	a[h - 1][w - 1] = '/';	a[h - 1][w + 2] = '\\';
	if (u < 10) {
		a[h - 1][w] = u + '0';
	} else {
		a[h - 1][w] = u / 10 + '0';
		a[h - 1][w + 1] = u % 10 + '0';
	}
	a[h - 2][w - 1] = '\\'; a[h - 2][w + 2] = '/';
	a[h - 2][w] = a[h - 2][w + 1] = '_';


}

void dfs(int h, int w, int u, int k) {
	draw_node(h, w, u);
	if (son[u][0] != -1) {
		dfs(h - 3 * (1 << k - 1), w - len[k] / 2 - 1, son[u][0], k - 1);
		int x = h - 3, y = w - 1;
		while (x >= (h - 3 * (1 << k - 1))) {
			a[x][y] = '/';
			-- x, -- y;
		}
	}

	if (son[u][1] != -1) {
		dfs(h - 3 * (1 << k - 1), w + len[k] / 2 + 1, son[u][1], k - 1);
		int x = h - 3, y = w + 2;
		while (x >= (h - 3 * (1 << k - 1))) {
			a[x][y] = '\\';
			-- x, ++ y;
		}
	}
}

void solve() {
    int n, k;
    std::cin >> n >> k;
    for (int i = 1; i <= n; ++ i) {
    	std::cin >> son[i][0] >> son[i][1];
    	if (son[i][0] > 0) {
    		++ in[son[i][0]];
    	}

    	if (son[i][1] > 0) {
    		++ in[son[i][1]];
    	}
    }

    len[1] = 4;
    for (int i = 2; i <= k; ++ i) {
    	len[i] = (len[i - 1] + 1) * 2;
    }

    int w = len[k];

    int h = 3 * (1 << k - 1);

    int root = 0;
    for (int i = 1; i <= n; ++ i) {
    	if (!in[i]) {
    		root = i;
    		break;
    	}
    }

    for (int i = 0; i < N; ++ i) {
    	for (int j = 0; j < N; ++ j) {
    		a[i][j] = ' ';
    	}
    }

    dfs(N - 5, N / 2, root, k - 1);

    int u = 0, d = N, l = N, r = 0;
    for (int i = 0; i < N; ++ i) {
    	for (int j = 0; j < N; ++ j) {
    		if (a[i][j] != ' ') {
    			u = std::max(u, i);
    			d = std::min(d, i);
    			l = std::min(l, j);
    			r = std::max(r, j);
    		}
    	}
    }

    -- l, ++ r, ++ u, -- d;
    for (int i = l; i <= r; ++ i) {
    	a[u][i] = a[d][i] = '*';
    }

    for (int i = d; i <= u; ++ i) {
    	a[i][l] = a[i][r] = '*';
    }

    for (int i = u; i >= d; -- i) {
    	for (int j = l; j <= r; ++ j) {
    		std::cout << a[i][j];
    	}
    	std::cout << "\n";
    }
}

K. 智乃的逆序数

题意:给你n个数组,每个数组里的数排序后都是一段连续的数,每个数组的数不重复。要求你用这些数组的数构造一个逆序对为k的数组,每个数组里的数在新数组里是它的子序列。

因为每个数组的数连续并且不会其他数组有相同的元素,那么这些数组从小到大排序后,逆序对数就等于每个数组的逆序对之和。因为前面数组的每个数一定比后面的任何一个数小,所以只需要计算每个数组的逆序对。然后我们模拟冒泡排序增加逆序对即可,注意不能和同一个数组的数交换。

点击查看代码
void solve() {
	int n, k;
	std::cin >> n >> k;
	std::vector<std::vector<int> > a(n);
	for (int i = 0; i < n; ++ i) {
		int m;
		std::cin >> m;
		while (m -- ) {
			int x;
			std::cin >> x;
			a[i].push_back(x);
		}
	}

	std::sort(a.begin(), a.end());

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

	n = ans.size();
	for (int i = 0; i < n; ++ i) {
		for (int j = i + 1; j < n; ++ j) {
			if (ans[i].first > ans[j].first) {
				-- k;
			}
		}
	}

	if (k < 0) {
		std::cout << "No\n";
		return;
	}

	for (int i = 0; i < n; ++ i) {
		int j = i;
		while (j > 0 && k > 0 && ans[j].second != ans[j - 1].second && ans[j].first > ans[j - 1].first) {
			-- k;
			std::swap(ans[j], ans[j - 1]);
			-- j;
		}
	}

	if (k > 0) {
		std::cout << "No\n";
		return;
	}

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

L. 智乃的三角遍历

题意:找一条路线恰好经过一次图形的所有边。这个图形是一个n层的三角形,每一层有i个三角形。

可以自己找一下方法,也可以打表。
我是每次从(i,i)出发,然后一直到(n,i),再往有走到(n,i1), 然后往上左右摇摆,走到(n1,i)(n1,i+1)。最后走到(i+1,i+1)。这样循环一直到(n,n)退出然后一路向上就行。

点击查看代码
void solve() {
	int n;
	std::cin >> n;
	std::cout << "Yes\n";
	std::cout << 1 << " ";
	int x = 1, k = 1;
	for (int i = 1; i <= n; ++ i) {
		// std::cout << i << "-----\n";
		while (k <= n) {
			x += k;
			std::cout << x << " ";
			k += 1;
		}

		k = n + 1;

		std::cout << x + 1 << " ";
		x += 1;
		while (k > i + 1) {
			std::cout << x - k << " " << x - k + 1 << " ";
			x -= k - 1;
			-- k;
		}
		k = i + 1;
		// std::cout << "\n";
	}

	k = n + 1;

	while (k > 1) {
		x -= k;
		std::cout << x << " ";
		-- k;
	}
}

M. 智乃的牛题

题意:判断给出的字符串能不能组成"nowcoder"。

排序比较是不是就行,比赛时没看见给出的字符串长度为8,写了个看是不是子序列的代码。

点击查看代码
void solve() {
	std::string s;
	std::cin >> s;
	std::string t = "nowcoder";
	std::sort(t.begin(), t.end());
	std::sort(s.begin(), s.end());
	int j = 0;
	for (int i = 0; j < t.size() && i < s.size(); ++ i) {
		if (s[i] == t[j]) {
			++ j;
		}
	}

	if (j == t.size()) {
		std::cout << "happy new year\n";
	} else {
		std::cout << "I AK IOI\n";
	}
}
posted @   maburb  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示