前面两道阅读理解直接跳过。
C - One Time Swap
大意
给定一个字符串,问交换任意两个字符,可以得到的不同字符串个数。
思路
令,为的第位和第位交换后得到的字符串。
考虑 ,但与重合的情况。
- 如果是,那么与只有 第个字符和第个字符不同。只有满足这一属性,并且是由操作产生的。
- 另一方面,如果,那么与相同。因此,对于的所有和 ,它都与 重合。
后者可以通过简单扫描来验证。
对于前者,我们不能枚举,否则会超时。
但我们可以统计中每个字符的出现次数,设为中第个小写字母的出现次数,那么总共有对。
可以直接计算,但我们也可以减去 和是相同字符的对,即
注意要开long long。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL cnt[26];
int main(){
LL n, ans=0;
bool flag = false;
string s;
cin >> s;
n = s.size();
for(int i = 0; i < n; i++) cnt[s[i] - 'a']++;
ans = n * n;
for(int i = 0; i < 26; i++){
ans -= cnt[i] * cnt[i];
if(cnt[i] > 1) flag = true;
}
ans /= 2;
if(flag) ans++;
cout << ans << endl;
return 0;
}
D - Tiling
大意
一块地板,长,宽,有块瓷砖可用,问是否可以选择若干块瓷砖,恰好铺满网格,瓷砖可旋转。
思路
由于数据范围很小,我们考虑暴力搜索。
设表示第行第个格子被哪一块瓷砖占用(没有被占用为-1)
为了表示哪些瓷砖可用,可以设二进制数,第位为1表示第块瓷砖可用。
由于瓷砖可以旋转(可以竖着放,也可以横着放),因此搜索时,每块瓷砖有两种情况(除了正方形)。
为了方便编写,我从dfs中分离出两个函数:
- 第一个函数尝试放置瓷砖并判断是否可行。
- 第二个函数用于回溯操作(由于第一个函数会改变,所以无论是否可行都要复原)。注意要判断是不是当前瓷砖,否则出现重叠时,会影响其他正常放置的瓷砖。
代码
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n, h, w;
cin >> n >> h >> w;
vector<int> A(n), B(n);
for(int i = 0; i < n; i++) cin >> A[i] >> B[i];
vector<vector<int>> c(h, vector<int>(w, -1));
bool ans = false;
auto place_tile = [&](int x, int y, int id, bool f) -> bool {
bool can = true;
int a = A[id], b = B[id];
if(f) swap(a, b);
for(int i = x; i < x + a; i++)
for(int j = y; j < y + b; j++){
if(i < h && j < w){
if(c[i][j] == -1) c[i][j] = id;
else can = false;
}else can = false;
}
return can;
};
auto do_backtrace = [&](int x, int y, int id, bool f){
int a = A[id], b = B[id];
if(f) swap(a, b);
for(int i = x; i < x + a; i++)
for(int j = y; j < y + b; j++)
if(i < h && j < w && c[i][j] == id) c[i][j] = -1;
};
auto dfs = [&](auto self, int unused, int x, int y){
while(c[x][y] >= 0){
y++;
if(y >= w) x++, y = 0;
if(x >= h) break;
}
if(x >= h){
ans = true;
return;
}
for(int i = 0; i < n; i++){
if(unused & (1 << i)){
bool can = place_tile(x, y, i, false);
if(can) self(self, unused ^ (1 << i), x, y);
do_backtrace(x, y, i, false);
if(A[i] != B[i]){
bool can = place_tile(x, y, i, true);
if(can) self(self, unused ^ (1 << i), x, y);
do_backtrace(x, y, i, true);
}
}
}
};
dfs(dfs, (1 << n) - 1, 0, 0);
cout << (ans? "Yes": "No") << endl;
return 0;
}