A. Fashion in Berland(Codeforces 691A)
思路
根据题意,只需要检查输入的序列中0的个数是否为1即可。另外需要特判夹克上只有一颗扣子的情况。
代码
#include <bits/stdc++.h>
using namespace std;
int n, a, cnt;
int main() {
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &a);
cnt += a;
}
if(n == 1) {
puts(cnt == 1 ? "YES" : "NO");
}
else {
puts(cnt == n - 1 ? "YES" : "NO");
}
return 0;
}
B. s-palindrome(Codeforces 691B)
思路
先建立一个映射表,将所有英文字母映射到与其具有对称结构的英文字母上,然后将字符串反转,再将其用映射表映射成另一个字符串。判断构造出来的字符串是否与原串相同即可。(下面代码构造映射表的方式太麻烦,用两个字符串来表示映射关系会更好)
#include <bits/stdc++.h>
using namespace std;
bool ok;
string s, t;
map <int, int> m;
void init() {
for(int i = 'A'; i <= 'z'; i++) {
m[i] = '#';
}
m['A'] = 'A'; m['H'] = 'H'; m['I'] = 'I';
m['M'] = 'M'; m['O'] = 'O'; m['T'] = 'T';
m['U'] = 'U'; m['V'] = 'V'; m['W'] = 'W';
m['X'] = 'X'; m['Y'] = 'Y'; m['b'] = 'd';
m['d'] = 'b'; m['o'] = 'o'; m['p'] = 'q';
m['q'] = 'p'; m['v'] = 'v'; m['w'] = 'w';
m['x'] = 'x';
}
int main() {
init();
cin >> s;
t = s;
reverse(t.begin(), t.end());
ok = true;
for(int i = 0; i < s.size(); i++) {
if(m[t[i]] != s[i]) {
ok = false;
}
}
puts(ok ? "TAK" : "NIE");
return 0;
}
C. Exponential notation(Codeforces 691C)
思路
- 如果输入的是小于
1
的数的话,就从小数点开始往后查找,找到第一个非零的数位,假设这个数位上的数是
x ,根据 x 与小数点的位置可以确定aEb 中的 b 是多少。最后先后将x 、小数点和 x 之后的非零数字拼接起来就是aEb 中的 a 。 - 如果输入的是大于或等于
1 的数的话,就从小数点开始向前查找,原理与上一个情况相同。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
char str1[maxn];
char str2[maxn];
int main() {
scanf("%s",str1);
int len_str1 = strlen(str1);
int point = len_str1;
for(int i = 0; i < len_str1; i++) {
if(str1[i]=='.') {
point = i;
break;
}
}
int flag_point;
int len_str2;
for(int i=0; i<len_str1; i++) {
if(str1[i]>'0'&&str1[i]<='9') {
str2[0]=str1[i];
str2[1]='.';
flag_point=i+1;
len_str2=1;
for(int j=i+1; j<len_str1; j++)
if(str1[j]>='0'&&str1[j]<='9')
str2[++len_str2]=str1[j];
break;
}
}
for(int i=len_str2; i>=1; i--) {
if(str2[i]=='0'||str2[i]=='.') {
len_str2--;
}
else {
break;
}
}
for(int i=0; i<=len_str2; i++) {
printf("%c",str2[i]);
}
if(point != flag_point) {
point>flag_point?printf("E%d\n",point-flag_point):printf("E%d\n",point-flag_point+1);
}
return 0;
}
D. Swaps in Permutation(Codeforces 691D)
思路
当允许两个位置进行交换操作时,这两个位置就发生了联系,而且在思考中我们可以发现这种联系是可交换的,也是可传递的。于是我们就可以用无向图表示这种联系。其中点用来表示位置,边用来表示位置之间的联系。
建图完毕后,图必然由若干个连通分量组成。连通分量的意义是,该分量中的位置上的数可以任意排序。根据题意,我们要让同一个分量中大的数排在前面,小的数排在后面,并且对每个分量做这样的排序。那么在完成排序后,总序列一定是符合条件的。
实现上,连通的信息可以用并查集维护(因为除连通信息外不需要用图的其它信息了),除此之外还需要一个从连通分量映射到该分量中所有点的表。这样就能快速地从连通分量中将数提取出来,排序后再放回。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
int n, m, u, v, a[maxn], p[maxn];
vector <int> vec, G[maxn];
void init() {
for(int i = 1; i <= n; i++) {
p[i] = i;
}
}
int Find(int x) {
return x == p[x] ? x : p[x] = Find(p[x]);
}
void Union(int x, int y) {
x = Find(x);
y = Find(y);
if(x == y) {
return;
}
p[x] = y;
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
init();
while(m--){
scanf("%d%d", &u, &v);
Union(u, v);
}
for(int i = 1; i <= n; i++) {
G[Find(i)].push_back(i);
}
for(int i = 1; i <= n; i++) {
if(G[i].size() == 1) {
continue;
}
vec.clear();
for(int idx : G[i]) {
vec.push_back(a[idx]);
}
sort(vec.begin(), vec.end(), [] (int x, int y) { return x > y; });
for(int j = 0; j < G[i].size(); j++) {
int idx = G[i][j];
a[idx] = vec[j];
}
}
for(int i = 1; i <= n; i++) {
printf("%d ", a[i]);
}
return 0;
}
E. Xor-sequences(Codeforces 691E)
思路
本题看上去是个复杂的计数问题,实则不然。对于题中的“异或序列”而言,其中的数字的排列方式是由异或模3这种运算决定的。也就是说数字的排列可以看成某种关系。数字
a
和
用图的观点看待这种关系的话,如果代表
a
的点和代表
于是问题就转化成了求邻接矩阵的
代码
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 105;
typedef long long ll;
template <class T>
struct matrix {
int n, m;
T a[maxn][maxn];
matrix(int n = 0, int m = 0): n(n), m(m) {
memset(a, 0, sizeof(a));
}
matrix modMul(matrix &b, T mod) const {
matrix tmp(n, b.m);
for(int i = 0; i < n; i++) {
for(int j = 0; j < b.m; j++) {
for(int k = 0; k < m; k++) {
T t = a[i][k] * b.a[k][j] % mod;
tmp.a[i][j] = (tmp.a[i][j] + t) % mod;
}
}
}
return tmp;
}
matrix modPow(T e, T mod) const {
matrix a = *this, tmp(n, n);
for(int i = 0; i < n; i++) {
tmp.a[i][i] = 1;
}
for(; e > 0; e >>= 1) {
if(e & 1) {
tmp = tmp.modMul(a, mod);
}
a = a.modMul(a, mod);
}
return tmp;
}
};
int n;
ll k, sum, a[maxn];
int main() {
cin >> n >> k;
if(k == 1) {
cout << n << endl;
return 0;
}
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
matrix <ll> mat(n, n), ans(n, n);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(bitset<64>(a[i] ^ a[j]).count() % 3 == 0) {
mat.a[i-1][j-1] = 1;
}
}
}
ans = mat.modPow(k - 1, mod);
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
sum = (sum + ans.a[i][j]) % mod;
}
}
cout << sum << endl;
return 0;
}
F. Couple Cover(Codeforces 691F)
思路
先将问题转化为求比
∑ni=11i=O(log(n))
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxa = 3e6;
ll n, a, all, m, q, num[maxa], sum[maxa];
int main() {
scanf("%I64d", &n);
all = n * (n - 1);
while(n--) {
scanf("%I64d", &a);
m = max(m, a);
num[a]++;
}
for(ll i = 1; i <= m; i++) {
for(ll j = 1; j <= m; j++) {
if(i * j > maxa) {
break;
}
if(i == j) {
sum[i*i] += num[i] * (num[i] - 1);
}
else {
sum[i*j] += num[i] * num[j];
}
}
}
for(ll i = 2; i <= maxa; i++) {
sum[i] += sum[i-1];
}
scanf("%I64d", &q);
while(q--) {
scanf("%I64d", &a);
printf("%I64d\n", all - sum[a-1]);
}
return 0;
}