题目顺序大致按照难度排序。
现在酒店中有单人间和双人间,价格分别是c1,c2,现在有n个队,每队三个人,性别分别用字母表示,当两个人性别相同且在同一个队时,他们可以住在双人间中。求最少需要多少钱使得n个队住下。
思路:直接模拟。
AC Code:
#include
typedef long long ll;
const int N = 1e5 + 5;
ll n, c1, c2;
std::string s;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> n >> c1 >> c2;
ll ans = 0;
for(int i = 1; i <= n; i ++) {
std::cin >> s;
std::sort(s.begin(), s.end());
if(s[0] == s[1] || s[1] == s[2]) {
ans += std::min(c1, c2) + std::min(c1 * 2, c2);
}
else
ans += std::min(c1, c2) * 3;
}
std::cout << ans << '\n';
return 0;
}
给出n个数的序列a,可以从中选择一些数字,但是如果选择了a[i],则要满足序列中所有长度为i的子串中最多有两个数被选到,现在求选择的数和最大是多少,注意,可以不选任何数。
思路:假设我们选择了三个数a[i]、a[j]和a[k],且k>j>i,那么在1~k区间内就会有三个数,不满足条件,可以得到最多选择两个数。排序贪心选择即可。
AC Code:
#include
typedef long long ll;
const int N = 1e5 + 5;
int n;
int a[N];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> n;
for(int i = 1; i <= n; i ++) {
std::cin >> a[i];
}
std::sort(a + 1, a + 1 + n, std::greater());
std::cout << std::max({0, a[1], a[1] + a[2]}) << '\n';
return 0;
}
有个人要准备c道题,他可以进行如下两种操作:花费a分钟克隆一个自己;花费b分钟准备一道题目。问准备c道题最少需要多长时间。
思路:最优选择一定是先尽可能快的克隆自己,然后最后一起花b分钟准备一道题,得到的计算式是,x是克隆的次数。
AC Code:
#include
typedef long long ll;
const int N = 1e5 + 5;
int t;
ll a, b, c;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
while(t --) {
std::cin >> a >> b >> c;
ll ans = 1e18;
for(int i = 0; i <= 30; i ++) {
ll res = 1 << i;
res = (ll)(ceil(c * 1.0 / res));
ans = std::min(ans, a * i + res * b);
}
std::cout << ans << '\n';
}
return 0;
}
给出n个字符串,对于一个字符串,若它的所有子串都出现在了这n个字符串中,则称这个字符串是good的,则最大的good串的长度是多少。
思路:可以从数据范围考虑起。若一个字符串能成为good字符串,且长度为x,那么它的x * (x + 1) / 2个子串都要出现,这样想good串长度最多是根下1e5级别,我们大约可以用350代替。然后考虑暴力,如果所有的串长度都是350,那一共最多有1e5 / 350个字符串,完全可以暴力,这样循环的时间复杂度是1e7级别,可以过。
AC Code:
#include
typedef long long ll;
const int N = 1e5 + 5;
int n;
std::string s[N];
std::unordered_map mp;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> n;
for(int i = 1; i <= n; i ++) {
std::cin >> s[i];
mp[s[i]] ++;
}
int ans = 0;
for(int i = 1; i <= n; i ++) {
int len = s[i].length();
bool flag = true;
for(int j = 0; j < len; j ++) {
for(int k = 1; k <= len; k ++) {
if(j + k - 1 >= len) continue;
std::string ss = s[i].substr(j, k);
if(!mp[ss]) {
flag = false;
break;
}
}
if(!flag) break;
}
if(flag)
ans = std::max(ans, (int)s[i].length());
}
std::cout << ans << '\n';
return 0;
}
给出函数f(x),回答t次询问,每次给出l和r,求区间[l, r]之间最大的f(x)是多少。
思路:f(x)的值可以联想到三进制,不过它是x的三进制加位数的和,那就直接贪心,使得三进制下每一位2的数量尽可能多。
AC Code:
#include
typedef long long ll;
const int N = 1e5 + 5;
int t;
ll f[N];
std::vector get3(ll x) {
std::vector vec;
while(x) {
int num = x % 3;
vec.push_back(num);
x /= 3;
}
reverse(vec.begin(), vec.end());
return vec;
}
ll getans(ll x) {
if(!x) return 1;
else if(x % 3 == 0) return getans(x / 3) + 1;
else return getans(x - 1) + 1;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
while(t --) {
ll l, r;
std::cin >> l >> r;
std::vector R = get3(r);
ll ans = std::max(getans(l), getans(r));
int n = R.size();
for(int i = 0; i < n; i ++) {
ll res = 0;
if(R[i] == 0) continue;
for(int j = 0; j < i; j ++) {
res = res * 3 + R[j];
}
res = res * 3 + R[i] - 1;
for(int j = i + 1; j < n; j ++) {
res = res * 3 + 2;
}
if(res >= l)
ans = std::max(ans, getans(res));
}
std::cout << ans << '\n';
}
return 0;
}
定义节点u的subtree(u)是以u为根的子树中所有节点的集合,现在称集合S是good的当且仅当它满足至少一个条件:1、对于S中所有不同的u和v,满足u是vsubtree中的一点或反之;2、对于S中所有不同的u和v,他们两个没有父子树关系。现给出一棵树,问可以划分的good集合数最小是多少。
思路:官方题解:
解释一下概念:链和反链是在简单有向无环图中定义的,在一条路径中出现的点,是在一条链上;不在一条路径上出现的点,即无法相互到达的点,是在一条反链上,形象的来说,在题目给定的树中,可以定义这棵树是以根节点为起始点的有向图,那么链就是在一条路径中的点,反链连接的就是若干叶子结点(也不一定都是叶子结点)。
AC Code:
#include
typedef long long ll;
const int N = 1e6 + 5;
int t, n;
int d[N], cnt[N], dep[N];
std::vector vec[N];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
while(t --) {
std::cin >> n;
for(int i = 1; i <= n; i ++) {
vec[i].clear();
d[i] = cnt[i] = dep[i] = 0;
}
for(int i = 2; i <= n; i ++) {
int u;
std::cin >> u;
d[u] ++;
vec[i].push_back(u);
}
std::queue q;
for(int i = 1; i <= n; i ++) {
if(!d[i]) {
q.push(i);
dep[i] = 1;
}
}
while(!q.empty()) {
int now = q.front();
q.pop();
for(auto u : vec[now]) {
dep[u] = dep[now] + 1;
d[u] --;
if(!d[u]) {
q.push(u);
}
}
}
for(int i = 1; i <= n; i ++) {
cnt[dep[i]] ++;
}
int ans = 2e9;
for(int i = 1; i <= n; i ++) {
ans = std::min(ans, cnt[i] + i - 1);
}
std::cout << ans << '\n';
}
return 0;
}
气,感觉铜牌题看了题解也不难,但是赛时想不到www
B是网络流?没学,爬了