Codeforces 15xx 合集
CF1525
A. Potion-making
直接输出约分后的分母即可。
B. Permutation Sort
这玩意看起来就不用很多次,如果本来就是有序的那么就是 \(0\),如果 \(a_1=1\) 或 \(a_n=n\) 那么显然只用 \(1\) 次。如果 \(a_n=1\) 且 \(a_1=n\) 那么显然需要 \(3\) 次,否则 \(2\) 次即可。
C. Robot Collisions
容易发现这东西和国际象棋里黑白象是类似的,奇数位置的不会和偶数位置的相撞,那么只用考虑奇偶性相同的点。然后只用使用一个栈来维护向右的点,如果只有一个向左的点在 \((x,0)\),我们可以把其看成一个在 \((-x,0)\) 的向右的点。最后再处理剩下所有向右的点,两两配对即可。
D. Armchairs
贪心是不对的,可以找到反例。这个时候看到数据范围我们想到dp,设 \(f_i\) 代表前 \(i\) 部分的答案,那么显然有 \(f_i=min(f_j+w(j+1,i))\),其中必须满足所有 \(1\) 都被 \(0\) 匹配,而 \(0\) 可以多于。接下来考虑计算 \(w(j+1,i)\),可以贪心计算,把最后的 \(1\) 与最后的 \(0\) 匹配即可。
E. Assimilation IV
根据期望的线性性我们只用考虑每个点的期望次数,即其概率。正难则反,考虑出现不了的概率。把所有可以使其出现的城市找出来,每次可以选一段后缀,将可以选的位置数乘起来,剩下的随便选,于是就做完了。
F. Goblins And Gnomes
首先发现这是个最小链覆盖,而最小链覆盖等于点数-二分图最大匹配,那么我们就是想要匹配尽量小。我们可以进行的一次操作就是找到一个点,然后把这点删了。显然,我们需要找到一个匹配的公共点,而这个点是一定存在的,不然匹配会加一。这个点很好找,预处理出最大独立集,然后在补集里删一个就好。考虑删点顺序,其实就是每次删多少点。这个直接 dp 就好了,总的复杂度是 \(O(n^3)\)。
CF1528
A. Parsa's Humongous Tree
仔细阅读样例解释,然后发现你会了。每个点只有可能取到区间的两个端点,于是直接dp即可。
B. Kavi on Pairing Duty
再次仔细阅读样例解释,发现只有两种可能。
-
若干段长度相同的线段平分。
-
若干条长度相同的线段镶嵌,然后中间部分构成子问题。
C. Trees of Tranquillity
容易发现答案是第一棵树从根到叶子这一条链的子集。于是考虑dfs的时候维护答案。考虑答案集合在第二棵树上的形态:如果把所有点搞在第二课树上建出虚树,那么一定是取所有叶子。于是维护虚树的叶子即可。发现每次加入只需判断是否存在一个点有祖先关系即可。
D. It's a bird! No, it's a plane! No, it's AaParsa!
观察发现这个答案不大,考虑直接跑dijkstra。如何处理等待?直接从 i 向 i+1 连一条长度为 1 的边。
E. Mashtali and Hagh Trees
首先思考什么情况是合法的,其实也就是一棵内向树、一棵外向树、一棵内向树+一条链+一棵外向树。外向树和内向树显然是双射,除了一条链的情况本质相同,所以我们只需要外向树计数即可,设 \(f_n\) 为最长链为 \(n\) 的外向树。先考虑二叉的情况,这个时候可以dp考虑。在 \(f_{n-1}\) 棵树中选 \(2\) 个的方案数直接可重集组合数,但是考虑到不一定要两棵树都是 \(n-1\),所以考虑容斥即可。还可以是一叉的情况,直接继承 \(f_{n-1}\) 即可。
求得 \(f_n\) 后,枚举链的长度,为了防止算重,强制链的两端都是三度点,设这样的方案是 \(g_n\),那么答案可以写成 \(\sum_{i=1}{n-2}\sum_{j=1}^{n-i-1}g_jg_{n-i-1}\),这个东西显然可以后缀和优化,可以 \(O(n)\) 求得。
F. AmShZ Farm
感觉这个翻译简化还不如不简化。
CF1535
A Fair Playoff
最大值小于最小值就不行。
B Array Reodering
先将奇偶分开,偶前奇后。容易发现这样最小。
C Unstable String
直接模拟,不是 \(?\) 的放栈里,然后稍微讨论一下即可。
D Playoff Tournament
写棵线段树模拟然后你就发现不用写线段树。。。
E Gold Transfer
贪心从上往下取,然后倍增维护就好。
F String Distance
以后注意看到这种数据范围就像根号分治(类比虚树)。先把同一字符集的放在一组,我们发现答案最多为 \(2\),至少为 \(1\)。什么时候为 \(1\)?即两个串切掉 \(lcp,lcs\) 后有一个串是升序的。
考虑 \(n\) 很小,直接枚举两个串然后模拟这个过程即可,复杂度 \(O(n^2|s|)\)。如果 \(|s|\) 很小,枚举每个串的每个子串,考虑有没有一个串是将这部分子串排序后的结果。但是这样会算重,我们只需把排完序后最前或最后不变的区间去掉即可。复杂度玄学 \(O(n|s|^2\log{s})\),所以调一下根号分治的块长就好了。
代码写得非常暴力,好像后一部分复杂度是 \(O(n|s|^3\log{s})\)。但是冲就完事。
#include <bits/stdc++.h>
#define register re
#define pc putchar
#define gc getchar
#define mp make_pair
#define pb push_back
#define pf push_front
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
namespace Standard_IO{
template <typename T>
void read(T &x) {
T flag = 1;
char ch = gc();
for (; !isdigit(ch); ch = gc()) if (ch == '-') flag = -1;
for (x = 0; isdigit(ch); ch = gc()) x = x * 10 + ch - '0';
x *= flag;
}
template <typename T>
void write(T x) {
if (x > 9) write(x / 10);
pc(x % 10 + '0');
}
template <typename T>
void print(T x) {
if (x < 0) pc('-'), x = -x;
write(x); pc(' ');
}
}using namespace Standard_IO;
string s[200005], t;
int n;
int len;
map<string, vector<string>> cla;
unordered_map<string, bool> mark;
int main() {
read(n);
for (int i = 1; i <= n; i++) {
cin >> t;
s[i] = t;
sort(t.begin(), t.end());
cla[t].pb(s[i]);
}
len = s[1].length();
ll ans = 0, before = 0;
for (auto jzyakioi : cla) {
vector<string> now = jzyakioi.second;
n = now.size();
ans += 1ll * n * before * 1337;
before += n;
if (n <= len * 250) {
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int lcp = 0, lcs = 0;
while (now[i][lcp] == now[j][lcp]) lcp++;
while (now[i][len - lcs - 1] == now[j][len - lcs - 1]) lcs++;
bool flag1 = 1, flag2 = 1;
for (int k = lcp + 1; k < len - lcs; k++) {
if (now[i][k] < now[i][k - 1]) {
flag1 = 0;
}
if (now[j][k] < now[j][k - 1]) {
flag2 = 0;
}
}
ans += 2;
if (flag1 || flag2) ans--;
}
}
} else {
ans += 1ll * n * (n - 1);
mark.clear();
for (auto x : now) mark[x] = true;
for (auto x : now) {
for (int i = 0; i < len; i++) {
for (int j = i; j < len; j++) {
string y = x;
sort(y.begin() + i, y.begin() + j + 1);
if (y[i] != x[i] && y[j] != x[j]) {//去重
if (mark[y]) {
ans--;
}
}
}
}
}
}
}
print(ans);
return 0;
}
CF1542
A. Odd Set
看奇数和偶数的数的个数相不相等即可。
B. Plus and Multiply
枚举所有 \(a^k\) 然后判断能不能加若干次 \(b\) 的到 \(n\)。
C. Strange Function
令 \(g(i)=\text{lcm}(1,2,\dots,i)\),不难发现答案为 \(\sum_{}i\times(\lfloor\frac{n}{g(i-1)}\rfloor-\lfloor\frac{n}{g(i)}\rfloor)\)
D. Priority Queue
考虑对于每个 \(x\) 的贡献,首先他得被选中,记这次操作为 \(X\),然后还不能被删掉。考虑对这样的 \(B\) 计数。形式化讲就是被选中后遇到减号时小于 \(x\) 的数的个数得大于 \(0\)。
考虑 \(dp\),记 \(f[i,j]\) 代表前 \(i\) 个操作有 \(j\) 个小于 \(x\) 的数的方案数(\(X\) 操作后,也就是说我们 dp 时是不包含操作 \(X\) 的。)。有如下转移:\(f[i,j]=f[i-1,j],f[i,(j-1,0)]=f[i-1,j](i<X),f[i,j-1]=f[i-1,j](i>X),f[i,j+1]=f[i-1,j](x_i<=x_X)\),注意遇到相同的时候加一个字典序就可以去重了。
E. Abnormal Permutation Pairs
思路来自神蛙。
\(f[i,j]\) 代表长度为 \(i\) 的两个排列逆序对之差为 \(j\) 的方案数。
由于这个 \(j\) 有可能是负数所以还需全部加上一个常数。
考虑从小到大枚举,有如下转移:
我们发现这是一个背包。而背包可以用生成函数来表示。
形式化来讲,第 \(i\) 个数的生成函数即为
于是上面直接转移,再做两次回退即可。至于回退背包是什么,你可以看看这道题 消失之物。
这一部分复杂度 \(O(n^3)\)。
在算答案的时候先枚举公共前缀的长度,然后枚举不同的数是哪两个,然后所需逆序对数即知道了。复杂度 \(O(n^3)\)。
CF1553
https://codeforces.com/contest/1553
A Digits Sum
统计 9 变成 10 的个数
B Reverse String
暴力模拟即可
C Penalty
暴力模拟即可
D Backspace
容易发现最后取完剩下一定是个偶数,然后中间每两个隔着的是奇数,且越晚取完越好,于是从后往前贪心即可
E Permutation Shift
对于一组排列我们从 \(a_i\to b_i\),然后数环的个数,设为 \(c\),最小 \(n-c\) 步。所以 \(n-c\le m\),所以 \(n-m\le c\),设自己到自己的数量是 \(k\),那么 \(c\le \frac{n+k}{2}\),所以 \(n-m\le \frac{n+k}{2}\),\(k\ge m\)。然后我们发现由于 \(m\le \frac{n}{3}\) 所以这样的排列最多就 \(3\) 个。于是我们就可以在 \(O(n)\) 的时间里求答案了。
这道题的思想就是不需要考虑全部情况,这在前几天的模拟赛里也遇到了同样的题。
F Pairwise Modulo
考虑增量构造,假设加入一个 \(b\),\(a\bmod b=a-[a/b]*b\),于是我们只用维护 \([a/b]\) 即可,直接枚举倍数,可以在 \(O(n\ln n)\) 里解决,在套一个树状数组,总复杂度 \(O(n\ln n\log n)\)。
G Common Divisor Graph
通过奇偶分析发现答案最多为 2,所以预处理一下就好了。
H XOR and Distance
在trie树上暴力即可。
I Stairs
通过一些推导可以知道容斥后方案数至于长度有关,所以直接枚举长度即可。
CF1555
A. PizzaForces
容易发现这是几个勾股数,所以第一二种不会用很多,直接枚举用几个即可
B. Two Tables
答案只有可能在四个角,直接枚举
C. Coin Rows
枚举 A 在哪里下去,然后 B 要不直接下去,要不在最后一格才下去
D. Say No to Palindromes
回文串只用管长度为 2 和 3 的,而这等价于任意三个连续的位置不能有相同的字符,于是确定了前三个位置后面的字符都确定了,枚举然后前缀和预处理
E. Boring Segments
按 w 排序,枚举最小值,和最大值,也就是一段区间,显然右端点有单调性,直接尺取+线段树判断
F. Good Graph
容易发现这是个仙人掌,于是动态维护仙人掌,使用LCT维护圆方树即可。当然还可以离线+树剖