ABC378合集
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;
}

浙公网安备 33010602011771号