A.炸鸡块哥哥的粉丝题
输出字符串的前 ⌈ n 2 ⌉ \lceil \frac{n}{2} \rceil ⌈2n⌉ 个字符
void solve()
{int n;string s;cin >> n >> s;cout << s.substr(0, (n + 1) / 2);
}
B.智乃想考一道鸽巢原理
当小球总个数为奇数时,贪心的留下 1 个小球,反之,留下 2 个小球,我们将这个值定义为 P ,即该颜色小球最小留下的个数。
常见的此类问题,我们只需要得到最大值,之后判断 t o t ≤ M a x { a i } × 2 tot\le Max\{a_i\} \times 2 tot≤Max{ai}×2 即可判断这个球是否会留下,但是这个题要求判断每一个小球是否能留下,要解决这个问题需要额外记录一个次大值即可解决。
void solve()
{ll n, mx = 0, sx = 0, tot = 0;ll p=1;cin >> n;vector<ll> a(n);for (ll &i : a){cin >> i;tot += i;if (i >= mx){sx = max(sx, mx);mx = i;}elsesx = max(i, sx);}if(tot%2==0)p=2;for (int i = 0; i < n; i++){if(a[i]<p)cout<< "0";else if ((a[i] == mx && (tot - p) >= sx * 2) || (tot - p) >= mx * 2)cout << "1";elsecout << "0";cout << " \n"[i == n - 1];}
}
C.智乃想考一道完全背包(Easy version)
首先我们注意到题目的要求
a 1 ≤ a 2 ≤ . . . ≤ a k ≥ a k + 1 ≥ . . . ≥ a n a_1 \le a_2\le...\le a_k\ge a_{k+1} \ge ... \ge a_n a1≤a2≤...≤ak≥ak+1≥...≥an
由这个限制条件我们很容易想到的是,当我们选取一个 K 以左的物品 a i a_i ai 时,我们必须保证 i → k i \to k i→k 这一段物品依次选取过一次,那么我们就可以对背包物品的体积和价值预处理一下。
for (int i = k - 1; i >= 1; i--){w[i] += w[i + 1];v[i] += v[i + 1];}for (int i = k + 1; i <= n; i++){w[i] += w[i - 1];v[i] += v[i - 1];}
然而当我们这样处理时,会导致第 K 个物品可能出现多余取的情况,如下图
为了解决这种情况,我们把这 N 个已被组合的区间互相组合一下,易证,最多会有 62500 个物品存在( M ≤ 500 M \le 500 M≤500,假定每个物品体积均为 1,最多左右 250 个物品直之间合并),之后对这些物品跑一遍完全背包,时间复杂度为 O ( m 3 4 ) O(\frac{m^3}{4}) O(4m3)
void solve()
{ll k, n, m;cin >> n >> m >> k;vector<ll> v(n + 1), w(n + 1), f(m + 10);for (int i = 1; i <= n; i++)cin >> w[i] >> v[i];for (int i = k - 1; i >= 1; i--){w[i] += w[i + 1];v[i] += v[i + 1];}for (int i = k + 1; i <= n; i++){w[i] += w[i - 1];v[i] += v[i - 1];}for (int i = 1; i <= k - 1; i++){for (int j = k + 1; j <= n; j++){if (w[i] + w[j] - w[k] <= m){w.push_back(w[i] + w[j] - w[k]);v.push_back(v[i] + v[j] - v[k]);}}}for (ll i = 1; i < v.size(); i++){for (ll j = w[i]; j <= m; j++)f[j] = max(f[j], f[j - w[i]] + v[i]);}for (int i = 1; i <= m; i++)cout << f[i] << " \n"[i == m];
}