A – Consecutive Sum Riddle
思博题,没什么好讲的。
// A.cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
ll n;
scanf("%lld", &n), printf("%lld %lld\n", -n + 1, n);
}
return 0;
}
B – Special Numbers
算乘方的题,没什么好讲的。直接二进制分解后类似快速幂做就行了。
// B.cpp
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int fpow(int bas, int tim)
{
int ret = 1;
while (tim)
{
if (tim & 1)
ret = 1LL * ret * bas % mod;
bas = 1LL * bas * bas % mod;
tim >>= 1;
}
return ret;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
int n, k;
scanf("%d%d", &n, &k);
int ret = 0, bas = 1;
while (k)
{
ret = (0LL + ret + bas * (k & 1)) % mod;
bas = 1LL * bas * n % mod;
k >>= 1;
}
printf("%d\n", ret);
}
return 0;
}
C – Make Them Equal
显然答案只有三种。零的结果显而易见,就是全 c 的情况。我们现在来分辨 1 和 2 的情况。
首先我们可以注意到,操作 n 和 n – 1 就可以把整个序列整理完,所以最差情况就是 2。
如何判断 1?
我们可以用调和级数的时间来标记那些非 c 位置的倍数,然后找一个没被标记的即可。
// C.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 3e5 + 200;
int T, n;
char str[MAX_N], cmdlet[10], rc;
bool vis[MAX_N];
int main()
{
scanf("%d", &T);
while (T--)
{
scanf("%d%s%s", &n, cmdlet, str + 1), rc = cmdlet[0];
bool flag1 = true;
for (int i = 1; i <= n; i++)
flag1 &= (str[i] == rc);
if (flag1)
puts("0");
else
{
if (str[n] == rc)
printf("1\n%d\n", n);
else
{
for (int i = 1; i <= n; i++)
vis[i] = true;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j += i)
if (str[j] != rc)
{
vis[i] = false;
break;
}
int pos = -1;
for (int i = 1; i <= n; i++)
if (vis[i])
pos = i;
if (pos != -1)
printf("1\n%d\n", pos);
else
printf("2\n%d %d\n", n - 1, n);
}
}
}
return 0;
}
D – The Number of Imposters
用并查集随便搞下啦。
// D.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200;
int T, n, m, ufs[MAX_N], siz[MAX_N];
char cmdlet[20];
int find(int x) { return ufs[x] == x ? x : ufs[x] = find(ufs[x]); }
void merge(int x, int y)
{
int fx = find(x), fy = find(y);
if (fx != fy)
ufs[fx] = fy, siz[fy] += siz[fx];
}
int main()
{
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= (n << 1); i++)
ufs[i] = i, siz[i] = (i <= n);
for (int i = 1, u, v; i <= m; i++)
{
scanf("%d%d%s", &u, &v, cmdlet + 1);
if (cmdlet[1] == 'i')
merge(u, v + n), merge(u + n, v);
else
merge(u, v), merge(u + n, v + n);
}
bool flag = true;
for (int i = 1; i <= n; i++)
flag &= (find(i) != find(i + n));
if (flag)
{
int ans = 0;
for (int i = 1; i <= n; i++)
if (find(i) == i)
ans += max(siz[find(i)], siz[find(i + n)]);
for (int i = n + 1; i <= (n << 1); i++)
if (find(i) == i)
ans += max(siz[find(i)], siz[find(i - n)]);
ans >>= 1;
printf("%d\n", ans);
}
else
puts("-1");
}
return 0;
}
E – Rubik’s Cube Coloring
两个版本放到一起讲。
首先,从 E1 可知,一个深度为 \(x\) 的子树的方案数为:
\[ 4^{2^x – 1} \]
那么对于 E2 而言,我们可以用类似 Trie 树的方式建出一个虚树,然后做一个 DP 就行了。范围很小,可以随便写。
实现起来有些细节,可以看代码。
// E2.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 200, mod = 1e9 + 7, opp[6] = {1, 0, 3, 2, 5, 4};
typedef long long ll;
int k, n, nodes[MAX_N][2], ptot, dep[MAX_N], tag[MAX_N], dp[MAX_N][6];
char cmdlet[10];
int mapper(char c)
{
switch (c)
{
case 'w':
return 0;
case 'y':
return 1;
case 'g':
return 2;
case 'b':
return 3;
case 'r':
return 4;
case 'o':
return 5;
}
return -1;
}
int fpow(int bas, int tim, int modulo)
{
int ret = 1;
while (tim)
{
if (tim & 1)
ret = 1LL * ret * bas % modulo;
bas = 1LL * bas * bas % modulo;
tim >>= 1;
}
return ret;
}
void insert(ll x, int typ)
{
int p = 1;
vector<int> seq;
while (x)
seq.push_back(x & 1LL), x >>= 1;
seq.pop_back();
reverse(seq.begin(), seq.end());
for (int c : seq)
{
if (nodes[p][c] == 0)
nodes[p][c] = ++ptot, dep[ptot] = dep[p] + 1;
p = nodes[p][c];
}
tag[p] = typ;
}
void dfs(int u)
{
int udp[2][6], sum[2];
memset(udp, 0, sizeof(udp)), sum[0] = sum[1] = 0;
for (int dir = 0; dir < 2; dir++)
if (nodes[u][dir])
{
dfs(nodes[u][dir]);
for (int d = 0; d < 6; d++)
udp[dir][d] = dp[nodes[u][dir]][d];
}
for (int d = 0; d < 6; d++)
sum[0] = (0LL + sum[0] + udp[0][d]) % mod, sum[1] = (0LL + sum[1] + udp[1][d]) % mod;
for (int d = 0; d < 6; d++)
if (d == tag[u] || tag[u] == -1)
{
int ls, rs;
if (nodes[u][0] == 0)
ls = fpow(4, (0LL + fpow(2, k - dep[u], mod - 1) + mod - 2) % (mod - 1), mod);
else
ls = (0LL + sum[0] + (mod - udp[0][d]) % mod + (mod - udp[0][opp[d]]) % mod) % mod;
if (nodes[u][1] == 0)
rs = fpow(4, (0LL + fpow(2, k - dep[u], mod - 1) + mod - 2) % (mod - 1), mod);
else
rs = (0LL + sum[1] + (mod - udp[1][d]) % mod + (mod - udp[1][opp[d]]) % mod) % mod;
dp[u][d] = 1LL * ls * rs % mod;
}
}
int main()
{
memset(tag, -1, sizeof(tag)), dep[1] = ptot = 1;
scanf("%d%d", &k, &n);
for (ll i = 1, u; i <= n; i++)
scanf("%lld%s", &u, cmdlet + 1), insert(u, mapper(cmdlet[1]));
dfs(1);
int ans = 0;
for (int d = 0; d < 6; d++)
ans = (0LL + ans + dp[1][d]) % mod;
printf("%d\n", ans);
return 0;
}