A. Palindromic Twist
由于必須改變。所以要使\(a[i] = a[n - i + 1]\)。
要么同向走,但必須滿足之前的\(a[i] = a[n - i + 1]\)。
要么相遇,必須滿足兩字符相差\(2\)的距離。
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
const int N = 110;
int n;
char str[N];
bool judge(){
for(int i = 1; i <= n / 2; i++)
if(abs(str[i] - str[n - i + 1]) != 2 && abs(str[i] - str[n - i + 1]) != 0) return false;
return true;
}
int main(){
int T; scanf("%d", &T);
while(T--){
scanf("%d%s", &n, str + 1);
if(judge()) puts("YES");
else puts("NO");
}
return 0;
}
B. Numbers on the Chessboard
找規律題,如果\(n\)是奇數,則每行有可能\((n - 1) / 2\) 或 \((n + 1) / 2\)個數字,可以分治考慮:
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
int n, q;
signed main(){
scanf("%lld%lld", &n, &q);
for(int i = 1; i <= q; i++){
int x, y; scanf("%lld%lld", &x, &y);
int num = 0;
if(n % 2){
if((x + y) % 2 == 0){
if(x % 2) num = (x - 1) * n / 2 + y / 2 + 1;
else num = (x - 2 + 1) * n / 2 + 1 + y / 2;
}else{
if(x % 2) num = n * n / 2 + 1 + (x - 1) * n / 2 + y / 2;
else num = n * n / 2 + (x - 2 + 1) * n / 2 + 1 + y / 2 + 1;
}
}else{
if((x + y) % 2 == 0){
if(x % 2) num = (x - 1) * (n / 2) + y / 2 + 1;
else num = (x - 1) * (n / 2) + y / 2;
}else{
if(x % 2) num = n * n / 2 + (x - 1) * (n / 2) + y / 2;
else num = n * n / 2 + (x - 1) * (n / 2) + y / 2 + 1;
}
}
printf("%lld\n", num);
}
return 0;
}
C. Minimum Value Rectangle
設矩形的兩邊長為\(a\)、\(b\),且\(a <= b\),則:
\(\frac{P ^ 2}{S} = \frac{(2(a + b)) ^ 2}{a * b}= \frac{4a ^ 2 + 4b ^ 2 + 8ab }{a * b} = 4(\frac{a}{b} + \frac{b}{a}) + 8\)
使\(\frac{a}{b} + \frac{b}{a}\) 最小,只需使\(\frac{b}{a}\)最小既可,因為\(\frac{b}{a} >= 1\),但\(\frac{a}{b} <= 1\),故后者對總和沒有影響。
#include <iostream>
#include <cstdio>
#include <limits.h>
#include <cstring>
#include <algorithm>
using namespace std;
const int SIZE = 10010;
int n, a, cnt[SIZE], d[SIZE << 1], tot, ansA, ansB;
double c, minn;
int main(){
int T; scanf("%d", &T);
while(T--){
memset(cnt, 0, sizeof cnt);
bool success = false; tot = 0;
minn = 10001;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a), cnt[a]++;
if(cnt[a] == 2) d[++tot] = a;
if(cnt[a] == 4) d[++tot] = a;
}
sort(d + 1, d + 1 + tot);
for(int i = 1; i < tot; i++){
if(d[i] == d[i + 1]){ ansA = d[i], ansB = d[i + 1]; break; }
c = (double)d[i + 1] / d[i];
if(c < minn)ansA = d[i], ansB = d[i + 1], minn = c;
}
printf("%d %d %d %d\n", ansA, ansA, ansB, ansB);
}
return 0;
}
D. Mouse Hunt
對于每個聯通塊,選擇環中(包括子環)的一個位置設置捕鼠夾既可。
在符合條件的位置上取最小值的和即為答案。
若選擇多個點,可證明其代價要大于選一個點。
若不選擇綠點,選擇1 + 20,但為了保證每個房間都能干掉老鼠,所以2000是必選的,所以選擇聯通快中多個點的花銷 > 只選一個點。
#include <iostream>
#include <cstdio>
#include <vector>
#include <limits.h>
using namespace std;
const int N = 200010;
int n, c[N], a[N], ans;
bool st[N], vis[N];
vector<int> G[N], edge, val;
void dfs(int u){
if(vis[u]){
val.push_back(u);
while(edge.size() && edge.back() != u)
val.push_back(edge.back()), edge.pop_back();
return ;
}
vis[u] = true, edge.push_back(u), dfs(a[u]);
}
void mark(int u){
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i];
if(!st[v]) st[v] = true, mark(v);
}
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", c + i);
for(int i = 1; i <= n; i++) {
scanf("%d", a + i);
G[i].push_back(a[i]);
G[a[i]].push_back(i);
}
for(int i = 1 ; i <= n; i++){
if(!st[i]){
val.clear(); edge.clear();
dfs(i);
int res = INT_MAX;
for(int i = 0; i < val.size(); i++)
res = min(res, c[val[i]]);
ans += res;
st[i] = true, mark(i);
}
}
printf("%d", ans);
return 0;
}
E. Inverse Coloring
自閉,看了題解之后稍微理解了一點點。
設\(f[i][j][k]\) 為長度為\(i\), 最長連續填色數為\(k\), 尾部最長連續涂色數最長為\(j\)的方案數
可以想到,這個狀態可以延展到的狀態有:
- 當新結尾顏色保持跟之前一樣,\(f[i + 1][j + 1][max(j + 1, k)]\)
- 不一樣,\(f[i + 1][1][max(1, k)]\)
\(cnt[i]\) 實際上是長度為\(i\)的所有方案數,那么只要符合:
\(i * j < k\),\(cnt[i] * cnt[j]\)就能被加入答案
…...
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 510, mod = 998244353;
typedef long long LL;
int n, k, f[2][N][N], cnt[N];
void update(int &a, int b){ a = (a + b) % mod; }
int main(){
scanf("%d%d", &n, &k);
f[0][0][0] = 1;
for(int i = 0; i < n; i++){
int pre = i & 1, now = pre ^ 1;
memset(f[now], 0, sizeof f[now]);
for(int j = 0; j <= n; j++){
for(int k = 0; k <= n; k++){
update(f[now][j + 1][max(j + 1, k)], f[pre][j][k]);
update(f[now][1][max(1, k)], f[pre][j][k]);
}
}
}
for(int i = 0; i <= n; i++){
for(int j = 0; j <= n; j++){
update(cnt[i], f[n & 1][j][i]);
}
}
LL ans = 0;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(i * j < k)
ans = (ans + (LL)cnt[i] * cnt[j]) % mod;
}
}
printf("%lld", (ans / 2) % mod);
return 0;
}