比赛名称:HHKB Programming Contest 2022 Winter(AtCoder Beginner Contest 282)
比赛链接:AtCoder Beginner Contest 282
给定字符串长度k,输出该字符串,该字符串由A,B,C
...拼接得到 。
#include
#define int long long
using namespace std;
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int k;
cin >> k;
for(char i = 'A'; i <= 'Z'; i++){
cout << i;
k--;
if(!k) break;
}
return 0;
}
给一个只有‘o''x'的字符矩阵,选两行,每一列至少一个’o',问有多少种方法
#include
using namespace std;
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector a(n);
for(auto &ai:a) cin >> ai;
int ans = 0;
for(int i = 0; i + 1 < n; i++){
for(int j = i + 1; j < n; j++){
bool flag = 1;
for(int k = 0; k < m; k++){
if(a[i][k] == 'o' || a[j][k] == 'o'){
}else{
flag = 0;
break;
}
}
if(flag) ans++;
}
}
cout << ans << "\n";
return 0;
}
" "外的','替换为'.'
这里要注意转义字符‘\"' = "
#include
using namespace std;
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
string s;
cin >> s;
bool flag = 0;
for(char &c:s){
if(c == '\"') flag ^= 1;
if(c == ',' && !flag) c = '.';
}
cout << s << "\n";
return 0;
}
题意:给定一张n个点的无向图,给其加一条边,满足其是二分图。问满足该条件的方案数
思路:
首先看二分图的概念:
就是顶点集可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。通俗地讲任何无回路的图均是二分图。
由于题目该图不一定是连通图,所以连通分量可能只有一个或多个,所以对此进行分类讨论:
只有一个连通分量:
该连通分量是否为一个二分图
- 是一个二分图,这时候只要我们在两个点集之间任意加条边即可,不会影响其二分图的性质,所以方案数有cnt1*cnt2(即两个点集的数量相乘)
- 不是一个二分图,如果不是一个二分图,无论怎么加边,都无法满足条件
有多个连通分量:
由上我们同样易证,只要任何一个连通分量不满足二分图,那么就无法满足条件
所以我们需要判断所有的连通分量是否都满足二分图性质
那么该条件下会贡献多少方案数呢?
答案是cnt1 * cnt2 + (cnt1 + cnt2) * (n - cnt1 - cnt2)
cnt1*cnt2上面已经证明过了
至于怎么得到(cnt1 + cnt2) * (n - cnt1 - cnt2)
我们可以发现由于所有的连通分量都是二分图,所以在不同的连通分量之间建边不会影响整体的二分图性质。
我们知道ans2是计算连通分量之间建边的方案数,所以同一条边会被重复计算两遍,所以最后要/2-总边数m
AcCode:
#include
#define int long long
using namespace std;
const int N = 2 * 1e5 + 6, M = 1e6 + 9;
int h[N], e[M], ne[M], idx;
int col[N];
int cnt1, cnt2;
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool dfs(int u, int c){
col[u] = c;
cnt1 += c == 0;
cnt2 += c == 1;
for(int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if(col[j] == -1){
if(!dfs(j, !c)) return false;
}else if(col[j] == c) return false;
}
return true;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
memset(h, -1, sizeof h);
memset(col, -1, sizeof col);
int d = m;
while(m--){
int a, b;
cin >> a >> b;
add(a, b), add(b, a);
}
int ans1 = 0, ans2 = 0;
for(int i = 1; i <= n; i++){
if(col[i] == -1){
cnt1 = 0, cnt2 = 0;
if(!dfs(i, 0)){
cout << 0 << "\n";
return 0;
}
ans1 += cnt1 * cnt2;
ans2 += (cnt1 + cnt2) * (n - cnt1 - cnt2);
}
}
cout << ans1 + ans2 / 2 - d;
return 0;
}
题意:
给定n个数,每个数范围[1,m−1],每次选择两个数x,y,获得 x^y+y^xmodm 分数。再将其中一个数丢弃,直至剩一个数。问获得的分数最大值。
思路:
刷题太少的缘故吧看了老半天也没看出来是啥题型,最后模拟一遍发现是个最大生成树模型。
怎么抽象出来呢?
我们可以发现在多轮的情况下,每个数可能被选多次,但是丢弃的话只要一次,一对多的关系很像树节点。
那么抽象出来就是每次删除叶子节点,获得叶子与父节点的边权值。
所以本题解题过程就是:建边,建图,跑最大生成树
AcCode
#include
using LL = long long;
using namespace std;
const int N = 550;
int p[N], a[N];
int n, m;
struct node{
int a, b, w;
}edge[N * N];
int qpow(int a, int b){
int ans = 1;
while(b){
if(b & 1) ans = (LL)ans * a % m;
b >>= 1;
a = (LL)a * a % m;
}
return ans;
}
bool cmp(node i, node j){
return i.w > j.w;
}
int find(int x){
if(p[x] == x) return x;
return p[x] = find(p[x]);
}
int f(int x, int y){
return (qpow(x, y) + qpow(y, x)) % m;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
int cnt = 0;
for(int i = 1; i <= n; i++){
for(int j = i + 1; j <= n; j++){
edge[++cnt] = {i, j, f(a[i], a[j])};
}
}
for(int i = 1; i <= n; i++) p[i] = i;
sort(edge + 1, edge + 1 + cnt, cmp);
LL ans = 0;
for(int i = 1; i <= cnt; i++){
int a = edge[i].a, b = edge[i].b, w = edge[i].w;
a = find(a), b = find(b);
if(a != b){
p[a] = b;
ans += w;
}
}
cout << ans << "\n";
return 0;
}
另外本题个点很迷惑,欢迎评论区大佬指正
find函数最开始这么写,一直出现自测RE
int find(int x){
return (p[x] == x ? x : (p[x] == find(p[x])));
}
改成下面这个形式就直接AC了....emmmm...仍百思不得其解
int find(int x){
if(p[x] == x) return x;
return p[x] = find(p[x]);
}