C. Game with Chips
题解
先将(k)个(chip)移到同一个点:左上角。然后,走(S)形遍历整个图就行了
最多操作次数: ((n - 1) + (m - 1) + (n * m - 1)) (<) (2 * n * m)。
(秒啊,没想到将它们移到同一点)
D. Infinite Path
题解
官方题解的描述实在蛋疼
推荐这位博主:https://blog.csdn.net/weixin_44178736/article/details/105180870?>
首先,一般都能观察到满足定义的(Infinite) (Path)构成了一个环,既存在(p[p[···p[i]]] = i)。实际上,一个排列 (p) 按照((i, p[i]))建边后形成的图恰好是由这样的环((Infinite) (Path))组成。模拟一下(p^k)的操作,发现(p^k)可以看做是每个点在环上不停的移动(k)次(动笔画一下比较好理解)。
然后,枚举(k)。记环的长度为(m),假设 (m) (\%) (k) (!= 0),那么对于任意一点,不停的移动,最终都会经过所有的点,等价于(k = 1),所以只需要枚举(m)的因数,将其作为(k)就行。实际上,有点类似离散数学中的:等价类。将原来的1个环划分为现在的(k)个环。
最后,检查这(k)个环中所有的点的颜色是否相同就行,满足的话更新答案。
复杂度的证明请看讨论:https://codeforces.com/blog/entry/75147
void Solve() {
int n;
scanf("%d", &n);
vector<int> p(n + 1), color(n + 1), use(n + 1, 0);
myfor(i, 0, n) scanf("%d", &p[i + 1]);
myfor(i, 0, n) scanf("%d", &color[i + 1]);
int ans = INF;
myfor(i, 0, n) if (!use[p[i + 1]]) {
int v = p[i + 1];
vector<int> cycle;
while(!use[v]) {
use[v] = 1;
cycle.push_back(v);
v = p[v];
}
myfor(step, 1, cycle.size() + 1) if (cycle.size() % step == 0) { // 枚举 k
myfor(j, 0, step) { // 枚举起点
bool flag2 = true;
//检查环中的每个点颜色是否相同
for (int k = j; k + step < cycle.size(); k += step) if (color[cycle[k]] != color[cycle[k + step]]) {
flag2 = false;
break;
}
if (flag2) {
ans = min(ans, step);
break;
}
}
}
}
cout << ans << endl;
return;
}
E. Count The Blocks
题解
①长度为(len)的块在中间
- (ans_{len} = (n - len - 1) * 10 * 9 * 9 * 10^{n - len - 2})
②长度为(len)的块在两端
- (ans_{len} = 2 * 10 * 9 * 10 ^{n - len - 1})
纯粹就是组合数学问题,类似于有m个座位,n个人坐在一起且相邻,既任意两个人之间没有空位,问有多少种方案。本题只是多了些限制条件
int n;
long long d[MAXN];
void Inite() {
d[0] = 1;
for (int i = 1; i < MAXN; ++i) d[i] = d[i - 1] * 10 % mod;
}
int main() {
cin >> n;
Inite();
for (int i = 1; i <= n; ++i) {
long long ans = 0;
if (n - i >= 2) ans = ((n - i - 1) * 81 * d[n - i - 1] % mod + ans) % mod;
if (n - i >= 1) ans = (18 * d[n - i] + ans) % mod;
else ans = (10 + ans) % mod;
cout << ans << " ";
}
cout << endl;
return 0;
}