Atcoder比赛题集
atcoder 题单
22/7/31比赛
C - Min Max Pair Editorial
题意转化为满足下列两种条件中的一种条件
a[i] == i && a[j] == j
a[i] == j && a[j] == i
第一种情况我们只需要记录数和下标相同的组数再用组合的公式
第二种情况详见代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
int same = 0;
for (int i = 0; i < n; ++i) {
cin >> a[i];
a[i] -= 1;
if (a[i] == i) {
same += 1;
}
}
long long ans = (long long)same * (same - 1) / 2;
for (int i = 0; i < n; ++i) {
if (a[i] > i and a[a[i]] == i) {
ans += 1;
}
}
cout << ans << '\n';
return 0;
}
这道题必须要想到可以通过检查每个i来计算满足后者的对的数量,因为一旦i是固定的,则j是唯一确定的。
这道题贪心,考场上想到了二的残次品没想到一,不过不知道为什么会有wa。
B - Triangle (Easier)
题目大意:给定一个无向图,求有几个只有三个点构成的环.
考场上想到深搜。
数据范围比较小,时间限制为两秒。然而这道题居然是久违的floyd判环,刚好符合数据大小N <= 100;
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector adj(n, vector<bool>(n));
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
u -= 1, v -= 1;
adj[u][v] = adj[v][u] = true;
}
int ans = 0;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
for (int k = j + 1; k < n; ++k) {
if (adj[i][j] and adj[j][k] and adj[k][i]) {
ans += 1;
}
}
}
}
cout << ans << '\n';
return 0;
}
D - I Hate Non-integer Number
题目大意,给定一个数列,求这个数列中的数组成的子数列的平均值为整数的个数,对答案取模.
如:2 4 2中有2,4,2,2 4,2 4,2 2.六个
N <= 100,ai <= 1e9.
口胡:先暴力处理子序列长度为1或为2的情况,记录每组数的奇偶性,在此基础上组合每次维护。
设dp[i][0/1]表示长度为i的子序列的平均值为偶/奇的个数
dp[i][0] += dp[j][0] * dp[i - j][0]
dp[i][0] += dp[j][1] * dp[i - j][1]
······
差不多是这意思
正解:是DP没错,但是三维
枚举选l个数,然后dp[i][j][k]表示前i个数选j个数%l的和为k的方案数
那么答案就是所有l情况下的dp[n][l][0]的和
在长度为x的子序列,可以发现可以由长度为x - 1的子序列和一个数得到。遵循拆分规律。比如3 2 3 4 5的%5为2,2 3 4 5的和%5 = 4剩下来的3加上去%5 = 2。其他数也有这个规律。
#include <bits/stdc++.h>
#include <atcoder/modint>
using namespace std;
using namespace atcoder;
using mint = modint998244353;
int main() {
int N;
cin>>N;
vector<int> a(N);
for(int i=0;i<N;i++)cin>>a[i];
mint ans = 0;
for(int i=1;i<=N;i++){
vector dp(N+1,vector(i+1,vector<mint>(i,0)));
dp[0][0][0] = 1;
for(int j=0;j<N;j++){
for(int k=0;k<=i;k++){
for(int l=0;l<i;l++){
dp[j+1][k][l] += dp[j][k][l];
if(k!=i)dp[j+1][k+1][(l+a[j])%i] += dp[j][k][l];
}
}
}
ans += dp[N][i][0];
}
cout<<ans.val()<<endl;
return 0;
}
A - mod M
显然答案为0或者1(%2),当最大公因数不为1时是1,否则是2.gcd的话是符合边减边模的,所以可以差分,不差分估计问题不大。
A - Continuous 1
/*
可以将整个字符串切成三段,第一段全是0,第二段只有1,第三段全是0.可以用前缀和来判断这个条件是否成立。
那么这道题的问号呢?
在长度为k的区间里,问号可以都能被替换成1,因为区间一共就k个数,那么区间外的问号自然也就是0,所以可以直接用前缀和来判断。
难点在于问号的处理。
*/
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n, k;
int a[N], b[N];
char s[N];
int main() {
int t;
scanf("%d", &t);
while(t--) { int ans=0, L=0, R=0;
scanf("%d%d", &n, &k);
cin>>s+1; s[n+1]='0', s[0]='0';
for(int i=1; i<=n; ++i) b[i]=b[i-1] + (s[i]=='1');
for(int i=1; i<=n; ++i) a[i]=a[i-1] + (s[i]=='0');
for(int i=k; i<=n; ++i) {
if(a[i]==a[i-k] && b[n]==b[i] && b[i-k]==0)
++ans;
}
if(ans==1) printf("Yes\n");
else printf("No\n");
}
return 0;
}