C. Game with Reversing
题目大意:A跟B玩游戏,给定两个字符串,A可以把其中一个字符串中的一个字符换成任意字符, B可以把两个字符串中的一个颠倒。当两个字符串完全相等时,游戏结束,A要尽量缩减时间,B要尽量延长时间,求游戏结束的最短时间。
思路:可以发现B颠倒哪个字符串无关紧要,偶数次等于没翻,奇数次等于翻一次。 设两个字符串正着比有cnt1个不同的,倒着比有cnt2个不同的。 我们只要为cnt1搭配最小偶数次,cnt2搭配最小奇数次,再求最小值即可(cnt1=0和cnt2=0时需要特判一下)。
void solve() {
int n;
cin >> n;
string s1, s2;
cin >> s1 >> s2;
int cnt1 = 0, cnt2 = 0;
for (int i = 0; i < n; i++)if (s1[i] != s2[i])cnt1++;
for (int i = 0; i < n; i++)if (s1[i] != s2[n - i - 1])cnt2++;
if (cnt1 == 0) {
cout << cnt1 << '\n';
return;
}
if (cnt2 == 0) {
cout << 2 << '\n';
return;
}
if (cnt1 % 2)cnt1 += (cnt1 - 1);
else cnt1 += cnt1;
if (cnt2 % 2)cnt2 += cnt2;
else cnt2 += (cnt2 - 1);
int ans = min(cnt1, cnt2);
cout << ans << '\n';
}
C. k-th equality
题目大意:输入a,b,c,k。a,b,c分别为各自位置上的位数,求满足a+b=c的第k个方案并输出。
思路:枚举a的所有情况,通过c的取值求出b满足条件的区间,即b的最小值和最大值。
typedef long long ll;
void solve() {
ll a, b, c, k;
cin >> a >> b >> c >> k;
ll x = 1, y = 1, z = 1;
while (--a)x *= 10;
while (--b)y *= 10;
while (--c)z *= 10;
for (ll i = x; i < x * 10; i++) {
ll l = max(y, z - i);
ll r = min(y * 10, z * 10 - i);
if (l > r)continue;
if (r - l >= k) {
cout << i << " + " << l + k - 1 << " = " << l + k - 1 + i << '\n';
return;
}
k -= r - l;
}
cout << "-1\n";
}
D. Apple Tree
题目大意:有一颗树,1-n个结点,根结点为1,给定一个n,再给出n-1条边,有两个苹果(苹果会掉落到与它相连并且编号比它小的结点上,若没有则掉落),q次查询,每一次查询给出两个苹果所在的节点x,y,输出有几种掉落方案。
思路:由于每一个结点上的苹果都会在叶子结点掉落,所以只需要找到每一个结点下面有多少个叶子结点即可。c[i]存储每一个结点下面有多少叶子结点(起初均为0),叶子结点下面只有一个叶子结点(本身)。从1开始dfs。
typedef long long ll;
ll c[200010];
vector<int>g[200010];
void dfs(int u, int fa) {
c[u] = 0;
int flag = 1;
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if (v == fa) continue; //判断是否为叶子结点
dfs(v, u);
flag = 0;
c[u] += c[v];
}
if(flag == 1){
c[u] = flag;
}
}
void solve() {
int n;
int a, b;
cin >> n;
for (int i = 0; i < n - 1; i++) {
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
dfs(1,0);
int q;
cin >> q;
while (q--) {
cin >> a >> b;
cout << c[a] * c[b] << '\n';
}
for (int i = 0; i <= n; i++)vector <int>().swap(g[i]); //清空
}
预祝端午节快乐!