A - Pairing
思路
排個序,比較相鄰元素。
程式碼
#include<iostream>
#include<algorithm>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
int a[5], ans;
int main(){
a[1] = read(), a[2] = read(), a[3] = read(), a[4] = read();
sort(a + 1, a + 5);
for (int i = 1; i <= 4; i++){
if (a[i] == a[i + 1]) i++, ans++;
}
cout << ans;
return 0;
}
B - Garbage Collection
思路
令 \(x\) 表示 \(d\mod q_t\) 的結果,那麼 \(x\le r_t\),答案就為 \(d + r_t - x\),否則答案就為 \(d + q_t + r_t - x\)。
程式碼
#include<iostream>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
const int N = 110;
int n, m;
int q[N], r[N];
signed main(){
n = read();
for (int i = 1; i <= n; i++) q[i] = read(), r[i] = read();
m = read();
for (int i = 1; i <= m; i++){
int t = read(), d = read(), x = d % q[t];
if (r[t] - x < 0) cout << d + (r[t] + q[t] - x) << '\n';
else cout << d + (r[t] - x) << '\n';
}
return 0;
}
C - Repeating
思路
設 \(q_{a_i}\) 表示 \(a_i\) 在當前掃描的字首裡出現最後的位置,如果遇到 \(a_i\) 輸出 \(q_{a_i}\),然後將 \(q_{a_i}\) 更新為 \(i\),由於 \(a_i\) 太大,用個 map 即可。
程式碼
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
const int N = 2e5 + 10;
int n;
int a[N];
map<int, int> q;
signed main(){
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++){
cout << (q[a[i]] == 0 ? -1 : q[a[i]]) << ' ';
q[a[i]] = i;
}
return 0;
}
D - Count Simple Paths
思路
對於每一個點作為起點進行深搜,若找到了長度為 \(k\) 的路徑,答案加 \(1\),在搜尋一次路徑時要打上標記,防止走迴路,搜尋完一個路徑後要回溯,清空標記。
程式碼
#include<iostream>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
const int N = 15;
int n, m, k, dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1}, ans;
bool a[N][N], vis[N][N];
void dfs(int x, int y, int sum){
if (vis[x][y]) return;
if (sum == k){
ans++;
return;
}
vis[x][y] = 1;
for (int i = 0; i < 4; i++){
int nx = x + dx[i], ny = y + dy[i];
if (nx < 1 || nx > n || ny < 1 || ny > m || !a[nx][ny]) continue;
dfs(nx, ny, sum + 1);
}
vis[x][y] = 0;
}
signed main(){
n = read(), m = read(), k = read();
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
char c; cin >> c;
if (c == '.') a[i][j] = 1;
}
}
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (a[i][j]) dfs(i, j, 0);
}
}
cout << ans;
return 0;
}
E - Mod Sigma Problem
思路
將題目要求的東西轉化一下,轉化為求以下的式子:
其中 \(sum_i\) 表示 \(1\) 到 \(i\) 之間的 \(a_i\) 的和,即字首和。
由於有一個模 \(m\),不好做,嘗試再轉化一下:
但是這一步的轉化是錯的,因為 \(sum_r\mod m\) 可能比 \(sum_{l - 1}\mod m\) 小,相減會出現負數,而原來的計算不會出現負數,這時答案要加上一個 \(m\),所以對於一個 \(r\),在 \(0\le l - 1\lt r\) 中,大於 \(sum_r\mod m\) 的 \(sum_{l - 1}\mod m\) 計算時都要加上 \(m\),用樹狀陣列統計有多少個這樣的 \(l - 1\),記為 \(X_r\),即為加上總的 \(m\) 的個數。對每個 \(sum_i\) 先對 \(m\) 取模,於是式子變成這樣:
其中,\(\sum\limits_{1\le l\le r} sum_{l - 1}\) 可以直接求,\(X_r\) 用樹狀陣列求。
程式碼
#include<iostream>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
const int N = 2e5 + 10;
int n, m, ans;
int a[N], sum[N];
int t[N];
int lowbit(int x){
return x & -x;
}
void add(int x, int k){
for (int i = x; i <= m; i += lowbit(i)) t[i] += k;
}
int query(int x){
int res = 0;
for (int i = x; i; i -= lowbit(i)) res += t[i];
return res;
}
signed main(){
n = read(), m = read();
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++) sum[i] = (sum[i - 1] + a[i]) % m;
int res = 0;
for (int i = 1; i <= n; i++){
ans += sum[i] * i - res + m * (query(m) - query(sum[i] + 1));
res += sum[i];
add(sum[i] + 1, 1);
}
cout << ans;
return 0;
}
F - Add One Edge 2
思路
題目要求連邊後這個環的所有點的度數為 \(3\),那麼連線的這兩個點的度數一定為 \(2\),其它環上的點的度數都為 \(3\),那麼在一個度數為 \(3\) 的點開始遍歷,找到連續的度數為 \(3\) 的點,直到找不了,於是這些度數為 \(3\) 的點相互連通,它們上面連線的度數為 \(2\) 的點任意兩兩連線都能形成一個符合題目要求的環,設這個連通的度數為 \(3\) 的點上面的度數為 \(2\) 的點的個數為 \(m\),那麼答案加上 \(\frac{m\times (m - 1)}{2}\)。
程式碼
#include<iostream>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
const int N = 2e5 + 10;
int n, res, ans;
struct edge{
int v, nxt;
}e[N << 1];
int head[N], cnt;
int in[N];
void add(int u, int v){
e[++cnt] = (edge){v, head[u]};
head[u] = cnt;
}
bool vis[N];
void solve(int u){
vis[u] = 1;
for (int i = head[u]; i; i = e[i].nxt){
int v = e[i].v;
if (vis[v]) continue;
if (in[v] == 3){
solve(v);
}
}
for (int i = head[u]; i; i = e[i].nxt){
int v = e[i].v;
if (!vis[v] && in[v] == 2) res++;
}
}
signed main(){
n = read();
for (int i = 1; i < n; i++){
int u = read(), v = read();
add(u, v), add(v, u);
in[u]++, in[v]++;
}
for (int i = 1; i <= n; i++){
if (in[i] == 3 && !vis[i]){
res = 0;
solve(i);
ans += res * (res - 1) / 2;
}
}
cout << ans;
return 0;
}