【题解】ABC292
被 F 这个神仙数学题卡了好久,再加上晚到了一会,这次就直接寄了,但是感觉这场 ABC 难度不高的样子 Ex 完全没有 Ex 该有的样子啊
A.CAPS LOCK
题目分析:
入门题,小写字母全部转大写。
代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
char s[1000];
int main(){
scanf("%s",s+1);
int n = strlen(s+1);
for(int i=1; i<=n; i++){
if(s[i] >= 'a' && s[i] <= 'z'){
s[i] = s[i] - 'a' + 'A';
}
}
for(int i=1; i<=n; i++) printf("%c",s[i]);
return 0;
}
B.Yellow and Red Card
题目分析:
直接对于每一个人统计一下其红牌和黄牌的数量,然后询问的时候根据条件判一下就好了。
代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int y[200],r[200];
int main(){
int n,q;
scanf("%d%d",&n,&q);
for(int i=1; i<=q; i++){
int opt,x;
scanf("%d%d",&opt,&x);
if(opt == 1){
y[x]++;
}
else if(opt == 2){
r[x]++;
}
else{
if(y[x] >= 2 || r[x]) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
C.Four Variables
题目分析:
可以考虑直接枚举 \(n = x + y\),然后考虑对于每一个数算出有多少种分解的方式,也就是统计 \(x = AB\) 的有序数对 \((A,B)\) 的方案数,记为 \(ans_x\),然后对于 \(n = x + y\) 的方案数就是 \(ans_x \times ans_y\),最终的方案数就是所有的加起来。
代码:
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e6+5;
int ans[N];
void pre(int mx){
for(int i=1; i<=mx; i++){
for(int j=i; j<=mx; j+=i){
ans[j]++;
}
}
}
signed main(){
int n;scanf("%lld",&n);
pre(n);
int sum = 0;
for(int i=1; i<=n; i++) sum = sum + ans[i] * ans[n-i];
printf("%lld\n",sum);
return 0;
}
D.Unicyclic Components
题目分析:
注意题意是:设对于每一个连通块有点数 \(V_i\) 和边数 \(E_i\),满足任意一个连通块都有 \(V_i = E_i\)。
知道了这个之后就直接上并查集维护连通性就好了。
代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int fa[N],sum1[N],sum2[N];
bool vis[N];
vector<int> v;
int find(int x){
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) fa[i] = i,sum1[i] = 1;
for(int i=1; i<=m; i++){
int from,to;scanf("%d%d",&from,&to);
from = find(from),to = find(to);
if(from != to){
fa[from] = to;
sum1[to] += sum1[from];sum1[from] = 0;
sum2[to] += sum2[from];sum2[from] = 0;
}
sum2[to]++;
}
for(int i=1; i<=n; i++){
int now = find(i);
if(!vis[now]){
v.push_back(now);vis[now] = true;
}
}
bool flag = true;
for(int i : v){
if(sum1[i] != sum2[i]){
flag = false;
}
}
if(flag) printf("Yes\n");
else printf("No\n");
return 0;
}
E.Transitivity
题目分析:
其实就是若存在 \(a \to b \to c\) 有边直接相连,那么就必须要存在 \(a \to c\) 有边直接相连。
那么这个时候就会发现如果存在 \(c \to d\) 有边直接相连,那么 \(a \to d\) 也要有边直接相连,因为 \(a \to c \to d\) 都是有边直接相连的。
也就是对于每一个点向它的每一个不直接相连但可以走到的点都必须有边相连,对于每一个点枚举一下统计一下就好了。
代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3+4;
struct edge{
int nxt,to;
edge(){}
edge(int _nxt,int _to){
nxt = _nxt,to = _to;
}
}e[2*N];
int ans = 0,n,m,cnt,head[N],dis[N];
bool flag[N][N];
void add_edge(int from,int to){
e[++cnt] = edge(head[from],to);
head[from] = cnt;
}
void get(int x){
memset(dis,0,sizeof(dis));
queue<int> q;
q.push(x);dis[x] = 1;
while(!q.empty()){
int now = q.front();q.pop();
for(int i = head[now]; i;i = e[i].nxt){
int to = e[i].to;
if(dis[to]) continue;
dis[to] = dis[now] + 1;
q.push(to);
}
}
for(int i=1; i<=n; i++){
if(dis[i] >= 3) ans++;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++){
int from,to;
scanf("%d%d",&from,&to);
add_edge(from,to);
flag[from][to] = true;
}
for(int i=1; i<=n; i++) get(i);
printf("%d\n",ans);
return 0;
}
G.Count Strictly Increasing Sequences
题目分析:
赛时感觉像一个找规律的题或者爆搜什么的,就很离谱。
但是好像是一个神仙 \(dp\),暂时没看懂,咕咕咕。
代码:
咕咕咕
Ex.Rating Estimator
题目分析:
(错失了一次可以场切 Ex 的机会,悲伤)
其实题目的关键就在于是否存在一个前缀使得它的平均值大于等于 \(B\),如果存在那么第一个这种前缀的平均值就是答案,否则就是整个序列的平均值就是答案。
那么关键问题就是怎么找这个前缀,直接维护平均值大概是实现不了的,所以就可以换一种角度啊,直接维护和,也就是维护一下前缀和与前缀全是 \(B\) 的情况下的和的差值,如果这个值大于等于 \(0\) 也同样可以说明这个前缀的平均值大于等于 \(B\),然后直接线段树就过了。
代码:
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5+5;
int n,b,q,a[N],tag[4*N],mx[4*N];
void pushdown(int now,int now_l,int now_r){
if(tag[now] != 0){
tag[now<<1] += tag[now];tag[now<<1|1] += tag[now];
mx[now<<1] += tag[now];mx[now<<1|1] += tag[now];
tag[now] = 0;
}
}
void modify(int now,int now_l,int now_r,int l,int r,int v){
if(l <= now_l && r >= now_r){
mx[now] += v;
tag[now] += v;
return;
}
pushdown(now,now_l,now_r);
int mid = (now_l + now_r)>>1;
if(l <= mid) modify(now<<1,now_l,mid,l,r,v);
if(r > mid) modify(now<<1|1,mid+1,now_r,l,r,v);
mx[now] = max(mx[now<<1],mx[now<<1|1]);
}
double query(int now,int now_l,int now_r){
if(now_l == now_r) return 1.0*(mx[now] + b * now_l) / now_l;
pushdown(now,now_l,now_r);
int mid = (now_l + now_r)>>1;
if(mx[now<<1] >= 0) return query(now<<1,now_l,mid);
return query(now<<1|1,mid+1,now_r);
}
signed main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
scanf("%lld%lld%lld",&n,&b,&q);
int sum = 0;
for(int i=1; i<=n; i++) scanf("%lld",&a[i]),sum += a[i];
for(int i=1; i<=n; i++) modify(1,1,n,i,i,-b*i);
for(int i=1; i<=n; i++) modify(1,1,n,i,n,a[i]);
for(int i=1; i<=q; i++){
int x,y;scanf("%lld%lld",&x,&y);
sum = sum - a[x] + y;
modify(1,1,n,x,n,-a[x] + y);
if(mx[1] < 0) printf("%.9f\n",1.0 * sum/n);
else printf("%.9f\n",query(1,1,n));
a[x] = y;
}
return 0;
}