A 和 C 都很扯(bushi,看看我的做题顺序就知道
A. Jiro
题意
给你三个符号 S A B , S A C , S B C S_{AB},S_{AC},S_{BC} SAB,SAC,SBC
定义:若
S
i
,
j
S_{i,j}
Si,j 为 >
,
i
>
j
i>j
i>j,否则
i
<
j
i<j
i<j
求 A , B , C A,B,C A,B,C 中第 2 2 2 大的值
思路
这道题不知道有没有更好的方法,但分类讨论思路比较清晰
{
a
>
b
:
b
>
c
:
b
b
<
c
:
a
>
c
:
c
a
<
c
:
a
a
<
b
:
b
<
c
:
b
b
>
c
:
a
<
c
:
c
a
>
c
:
a
\begin{cases} a>b: \\ \ \ \ \ b>c:b \\ \ \ \ \ b<c: \\ \ \ \ \ \ \ \ \ a>c:c \\ \ \ \ \ \ \ \ \ a<c:a \\ a<b: \\ \ \ \ \ b<c: b \\ \ \ \ \ b>c: \\ \ \ \ \ \ \ \ \ a<c:c \\ \ \ \ \ \ \ \ \ a>c:a \end{cases}
⎩
⎨
⎧a>b: b>c:b b<c: a>c:c a<c:aa<b: b<c:b b>c: a<c:c a>c:a
C++ 代码
#include<bits/stdc++.h>
using namespace std;
char ab,ac,bc;
int main(){
cin>>ab>>ac>>bc;
if(ab=='>'){
if(bc=='>'){
cout<<'B';
}else{
if(ac=='>'){
cout<<'C';
}else{
cout<<'A';
}
}
}else{
if(bc=='<'){
cout<<'B';
}else{
if(ac=='<'){
cout<<'C';
}else{
cout<<'A';
}
}
}
return 0;
}
B. Taro
题意
n
n
n 个 家庭,按顺序 出生
m
m
m 个婴儿,每次婴儿出生于第
A
i
A_i
Ai 个家庭,性别为
B
i
B_i
Bi(男性为 M
,女性为 F
)
判断第
i
(
1
≤
i
≤
m
)
i\ (1 \le i \le m)
i (1≤i≤m) 个婴儿是 ( Yes
) 否 ( No
) 是 第
A
i
A_i
Ai 个家庭的最早出生的 男性 婴儿(称为 Taro
)。
思路
用一个 used[n]
数组记录第
i
i
i 个家庭是否已经有了 Taro
每次输入时,若是女性,直接输出 No
后跳过
否则判断 used[a_i]
是否为
1
1
1
若是,输出 No
;否则输出 Yes
并把 used[a_i]
标为
1
1
1
C++ 代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
bool used[maxn];
int main(){
int n,m;
cin>>n>>m;
for(int i=0;i<m;i++){
int ai;
char c;
cin>>ai>>c;
if(c=='F'){
cout<<"No"<<endl;
}else{
if(!used[ai]){
cout<<"Yes"<<endl;
used[ai]=true;
}else{
cout<<"No"<<endl;
}
}
}
return 0;
}
C. Make Isomorphic
题意
题意很复杂
给你两个无向图 G G G 和 H H H,有 N N N 个顶点,分别 M G M_G MG 和 M H M_H MH 条边。
给你在每两个点删掉一条边或加上一条边的代价,你需要在 H H H 上添加或删减边,使得 H H H 与 G G G 同构
求最小总代价
同构定义:
除去顶点索引可以不一样,其它两张图形状相同,换句话说
把 { 1 , 2 , . . . , n } \{1,2, \ ..., \ n\} {1,2, ..., n} 进行重排,变成 { p 1 , p 2 , . . . , p n } \{p_1,p_2,\ ..., \ p_n \} {p1,p2, ..., pn},当且仅当 ( i , j ) (i,j) (i,j) 有边时, ( p i , p j ) (p_i,p_j) (pi,pj) 有边
思路
需要用到 next_permutation()
函数,引用 bits/stdc++.h
头文件后即可使用
此函数共
2
2
2 个参数,next_permutation(a+1,a+n+1)
代表下标从
1
1
1 开始的
a
a
a 数组的 下一个排列(按照字典序)
由于 N ≤ 8 N \le 8 N≤8,所以最多有 8 ! = 40320 8!=40320 8!=40320 种排列方式,直接枚举全排列即可
图结构考虑用邻接矩阵存储,而不用邻接表,因为要快速查找 ( i , j ) (i,j) (i,j) 之间是否有边
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=2e9;
const int maxn=10;
int tab[maxn][maxn];
int n;
int ng,nh;
bool g[maxn][maxn],h[maxn][maxn];
int pt[maxn];
signed main(){
//输入
cin>>n>>ng;
for(int i=0;i<ng;i++){
int ai,bi;
cin>>ai>>bi;
g[ai][bi]=true;
g[bi][ai]=true;
}
cin>>nh;
for(int i=0;i<nh;i++){
int ai,bi;
cin>>ai>>bi;
h[ai][bi]=true;
h[bi][ai]=true;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
cin>>tab[i][j];
tab[j][i]=tab[i][j];
}
}
//初始化排列
for(int i=1;i<=n;i++){
pt[i]=i;
}
//开始枚举全排列
int ans=inf;
do{
int res=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) continue;
if(g[i][j]!=h[pt[i]][pt[j]]){
res+=tab[pt[i]][pt[j]];
}
}
}
//因为是无向图每条边的代价都会被算2次,所以要在最后除以2
ans=min(ans,res/2);
}while(next_permutation(pt+1,pt+1+n));
cout<<ans<<endl;
return 0;
}
D. 1D Country
题意
N N N 个村庄,每个村庄在 X i X_i Xi 的位置,有 P i P_i Pi 个村民
回答 Q Q Q 次询问:找到位置 L L L 到 R R R 之间的村民总个数
思路
考虑前缀和,其中 s u m 0 = 0 sum_0=0 sum0=0
每次给的 L L L 和 R R R 用二分查找定位,最终相减。
注意下标越界的情况,若下界小于 0 0 0 则把他的值重新变为 0 0 0
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int32_t t=1;
const int maxn=200005;
int n,q;
int x[maxn],sum[maxn];
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>x[i];
}
for(int i=1;i<=n;i++){
int ai;
cin>>ai;
sum[i]=sum[i-1]+ai;
}
cin>>q;
while(q--){
int l,r;
cin>>l>>r;
int L=lower_bound(x+1,x+1+n,l)-x;
int R=upper_bound(x+1,x+1+n,r)-x-1;
if(L>R){
cout<<0<<endl;
}else{
L--;
if(L<0) L=0;
cout<<sum[R]-sum[L]<<endl;
}
}
return 0;
}
E. I Hate Sigma Problems
题意
给你 a a a 数组,定义 f ( i , j ) f(i,j) f(i,j) a a a 数组中,下标从 i i i 到 j j j 共有多少个不同种类的数字
求 ∑ i = 1 N ∑ j = 1 N f ( i , j ) \displaystyle \sum_{i=1}^N \sum_{j=1}^N f(i,j) i=1∑Nj=1∑Nf(i,j)
思路
对于每个 i i i, 考虑下标起点为 i i i 的子数组
正常情况下若不重复, f ( i , j ) f(i,j) f(i,j) 的值 ( j ≥ i ) (j\ge i) (j≥i) 依次为 1 , 2 , 3 , . . . , n − i + 1 1,2,3,\ ..., \ n-i+1 1,2,3, ..., n−i+1
但是,出现了重复,那么在重复的地方,后面每个都减一
那么我们预处理出总共需要减去的数即可,其余部分用等差数列求和公式进行求和
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=200005;
int a[maxn];
queue<int> v[maxn];
int n;
int sum;
int ans;
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
v[a[i]].push(n-i+1);
if(v[a[i]].size()>1){
sum+=(n-i+1);
}
}
for(int i=1;i<=n;i++){
int res=(1+(n-i+1))*(n-i+1)/2;
v[a[i]].pop();
ans+=res-sum;
if(v[a[i]].size()>=1){
sum-=v[a[i]].front();
}
}
cout<<ans<<endl;
return 0;
}