文章目录
一、概况
比赛名称:Codeforces Round 719 (Div. 3)
日期:2024/3/3
题非常简单,但只做出两个……
把一些简单的题想复杂了,最终没做出来。
二、正解
C. Not Adjacent Matrix
1 题目描述
构造一个 n ∗ n n*n n∗n 的矩阵,使得相邻的两个格子填的数不能相邻。
2 大体思路
有许多中构造方式,最简单的:先打印所有奇数,后打印所有偶数(范围内)。
3 AC代码
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
int main(){
ll t;
cin>>t;
while(t--){
ll n;
cin>>n;
if(n==1){
cout<<1;pr;
}
else if(n==2){
cout<<-1;pr;
}
else{
ll x=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<x<<" ";x+=2;
if(x>n*n){
x=2;
}
}
pr;
}
}
}
return 0;
}
D. Same Differences
1 题目描述
给出 T T T 组序列 a a a,长度为 N N N,询问有多少对 ( i , j ) (i,j) (i,j) 满足 i < j i < j i<j 且 a j − a i = j − i a_j - a_i = j - i aj−ai=j−i。
2 大体思路
改写一下原题的等式:
a
j
−
j
=
a
i
−
i
a_j - j = a_i - i
aj−j=ai−i
把每个
a
i
a_i
ai 换成
b
i
=
a
i
−
i
b_i = a_i - i
bi=ai−i 答案就变成了求
(
i
,
j
)
(i,j)
(i,j) 中有多少对
i
<
j
i \lt j
i<j 且
b
i
=
b
j
b_i = b_j
bi=bj 。
3 AC代码
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
#pragma GCC optimize(2)
using namespace std;
int main(){
ll t;
cin>>t;
while(t--){
ll n,ans=0;
cin>>n;
map<ll,ll> ma;
for(int i=0;i<n;i++){
ll x;
cin>>x;
x-=i;
ans+=ma[x];
ma[x]++;
}
cout<<ans;pr;
}
return 0;
}
E. Arranging The Sheep
1 题目描述
共有
t
t
t 组数据,每组数据第一行为
n
n
n ,为字符串长度,下一行为一个字符串(只有 .
和 *
字符),每次可以向右或者向左移动 *
字符,求把所有的 *
字符连起来的最小移动次数。
2 大体思路
回想一下,你上体育课的时候老师是不是让你向中间的学生靠拢?因为这样移动距离最短。同理,我们让所有 *
都向最中间的 *
移动。
3 AC代码
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
string s;
ll n,m[1000005],top,flag,ans,t;
int main(){
cin>>t;
while(t--){
top=0,flag=0,ans=0;
cin>>n>>s;
for(int i=0;i<n;i++){
if(s[i]=='*'){
m[++top]=i+1;
}
else{
flag=1;
}
}
if(top==0||top==1||flag==0){
cout<<0;pr;continue;
}
ll mid=top/2+1;
for(int i=1;i<=top;i++){
ans+=abs(m[mid]-m[i])-abs(mid-i);
}
cout<<ans;pr;
}
return 0;
}
F1. Guess the K-th Zero (Easy version)
1 题目描述
交互题。给定 n , t , k n,t,k n,t,k(由于这里是简单版,保证 t = 1 t=1 t=1,即 t t t 没啥用),有一个长度为 n n n 的标号为 1 ⋯ n 1\cdots n 1⋯n 的仅含 01 01 01 的数组,你每次可以询问 l l l 到 r r r 的和,需要得出数组中第 k k k 个 0 0 0 的下标。最多询问 20 20 20 次。
2 大体思路
二分
假设当前的线段是
[
l
,
r
]
[l, r]
[l,r] ,我们想在它上面找到
k
k
k -th zero。查询
[
l
,
m
]
[l, m]
[l,m] 段的一半,即
m
=
l
+
r
2
m = \frac{l+r}{2}
m=2l+r 。
如果左半段至少有
k
k
k 个0,那么我们就去左半段寻找
k
k
k 个0。如果左半边只有
x
<
k
x \lt k
x<k 个0,那么我们就去右边的线段寻找
(
k
−
x
)
(k-x)
(k−x) 个0。
3 AC代码
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
void check(ll l,ll r,ll k){
if(l==r){
cout<<"! "<<l<<endl;
return;
}
ll m=(l+r)/2;
cout<<"? "<<l<<" "<<m<<endl;
ll sum;
cin>>sum;
if((m-l+1)-sum>=k){
check(l,m,k);
}
else{
check(m+1,r,k-(m-l+1)+sum);
}
}
int main(){
ll n,t,k;
cin>>n>>t>>k;
check(1,n,k);
}
G. To Go Or Not To Go?
1 题目描述
给定一个
n
×
m
n\times{m}
n×m 的网格,每个格子
(
i
,
j
)
(i,j)
(i,j) 都有一个整数参数
a
i
j
(
−
1
≤
a
i
j
≤
1
0
9
)
a_{ij}(-1\leq a_{ij}\leq10^9)
aij(−1≤aij≤109) ,
a
i
j
=
−
1
a_{ij}=-1
aij=−1 表示这个格子不能通过;否则,这个格子可以通过,若
a
i
j
>
0
a_{ij}>0
aij>0 则表示这个格子内有一个传送门。
现在小D想要从
(
1
,
1
)
(1,1)
(1,1) 移动到到
(
n
,
m
)
(n,m)
(n,m) ,它可以以如下两种方式移动:
- 在任意两个相邻且参数均不为 − 1 -1 −1的格子间移动,花费为 w w w ;
- 在有传送门的两个格子 ( i , j ) (i,j) (i,j) 和 ( x , y ) (x,y) (x,y) 间移动,花费为 a i j + a x y a_{ij}+a_{xy} aij+axy 。
求小D所需的最小花费。
2 大体思路
在传送门之间使用两次转换是没有意义的,因为如果从传送门
A
A
A 到传送门
B
B
B ,然后从传送门
B
B
B 到传送门
C
C
C ,那么不如从传送门
A
A
A 转到传送门
C
C
C ,这样花费更少。
那么就有两条可能的路径。
第一种–不使用传送门。这里只需找到两点之间的最短路径即可。
第二种–使用单一传送门。显然,这个传送门的距离和转换成本都是最小的。