博主Rating现在才 1543 1543 1543,仅代表个人观点,如有不同的见解,欢迎在评论区提出
A. Minimize!
题意
给你 a a a 和 b b b,找到一个 c ( a ≤ c ≤ b ) c \ (a\le c\le b) c (a≤c≤b),使得 ( c − a ) + ( b − c ) (c-a)+(b-c) (c−a)+(b−c) 最小
思路
原式可化简为 c − a + b − c = − a + b = b − a c-a+b-c=-a+b=b-a c−a+b−c=−a+b=b−a,所以直接输出 b − a b-a b−a
C++ 代码
#include<bits/stdc++.h>
using namespace std;
int t;
int main(){
cin>>t;
while(t--){
int a,b;
cin>>a>>b;
cout<<b-a<<endl;
}
}
B. osu!mania
题意
你有一个
n
n
n 行
4
4
4 列的矩阵,每一行包含 .
和 #
,要求对于每个
i
(
n
≥
i
≥
1
)
i \ (n \ge i \ge 1)
i (n≥i≥1),找到 #
的位置(从最后一行开始)
思路
直接按题意模拟
C++ 代码
#include<bits/stdc++.h>
#define sz(v) (int)v.size()
using namespace std;
int t;
void solve(){
int n;
cin>>n;
vector<int> ans;
for(int i=0;i<n;i++){
string s;
cin>>s;
for(int j=0;j<4;j++){
if(s[j]=='#'){
ans.push_back(j+1);
}
}
}
for(int i=sz(ans)-1;i>=0;i--){
cout<<ans[i]<<" ";
}
cout<<endl;
}
int main(){
cin>>t;
while(t--){
solve();
}
return 0;
}
C. The Legend of Freya the Frog
题意
给你 x , y , k x,y,k x,y,k,在一个平面上,你要从 ( 0 , 0 ) (0,0) (0,0) 走到 ( x , y ) (x,y) (x,y) ,每次可以跳 d ( 1 ≤ d ≤ k ) d\ (1 \le d \le k) d (1≤d≤k) 步。第奇数次往右跳,即移动到 ( c u r x , c u r y + d ) (curx,cury+d) (curx,cury+d) ,偶数次往下跳,即移动到 ( c u r x + d , c u r y ) (curx+d,cury) (curx+d,cury),问至少跳多少次可以到达 ( x , y ) (x,y) (x,y)
思路
分别考虑只往右的次数
(
r
i
g
h
t
)
(right)
(right) 和只往下的次数
(
d
o
w
n
)
(down)
(down):
{
d
o
w
n
=
(
y
+
k
−
1
)
/
k
∗
2
i
f
(
(
x
+
k
−
1
)
/
k
>
(
y
+
k
−
1
)
/
k
)
)
:
r
i
g
h
t
=
(
x
+
k
−
1
)
/
k
∗
2
−
1
e
l
s
e
:
r
i
g
h
t
=
(
x
+
k
−
1
)
/
k
∗
2
\begin{cases} down=(y+k-1)\ /\ k*2 \\ \\ if((x+k-1)/k>(y+k-1)/k)): \\ \ \ \ \ \ \ \ \ right=(x+k-1)/k*2-1 \\ else: \\ \ \ \ \ \ \ \ \ right=(x+k-1)/k*2 \end{cases}
⎩
⎨
⎧down=(y+k−1) / k∗2if((x+k−1)/k>(y+k−1)/k)): right=(x+k−1)/k∗2−1else: right=(x+k−1)/k∗2
注:此处
(
a
+
b
−
1
)
/
b
(a+b-1)/b
(a+b−1)/b 表示
⌈
b
a
⌉
\displaystyle \lceil \frac{b}{a} \rceil
⌈ab⌉
最后取 max ( d o w n , r i g h t ) \max(down,right) max(down,right) 就可以了
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t;
void solve(){
int n,m,k;
cin>>n>>m>>k;
int right=(n+k-1)/k*2;
if((n+k-1)/k>(m+k-1)/k){
right--;
}
int down=(m+k-1)/k*2;
cout<<max(down,right)<<endl;
}
signed main(){
cin>>t;
while(t--){
solve();
}
return 0;
}
D. Satyam and Counting
题意
给你平面上的 n n n 个点 ( x i , y i ) (x_i,y_i) (xi,yi),要求你找到用这些点构成的 直角三角形 的个数,保证 y i ∈ { 0 , 1 } y_i \in \{0,1\} yi∈{0,1}
思路
3 3 3 个点能构成一个直角三角形,当且仅当 满足一下条件 之一:
- 存在 ( x i , y i ) , ( x j , y j ) (x_i,y_i),(x_j,y_j) (xi,yi),(xj,yj),使得 x i = x j x_i=x_j xi=xj 且 y i ! = y j y_i!=y_j yi!=yj,此时可以与除这两点外的任意一点构成直角三角形
- 存在
(
x
i
,
y
i
)
,
(
x
j
,
y
j
)
,
(
x
k
,
y
k
)
(x_i,y_i),(x_j,y_j),(x_k,y_k)
(xi,yi),(xj,yj),(xk,yk) ,使得
x
i
+
1
=
x
j
=
x
k
−
1
x_i+1=x_j=x_k-1
xi+1=xj=xk−1 且
y
i
≠
y
j
≠
y
k
,
y
i
=
y
k
y_i\ne y_j \ne y_k, \ y_i=y_k
yi=yj=yk, yi=yk,此时构成一个 等腰直角 三角形
- 证明:这种情况下与垂线的最小夹角也是 45 ° 45° 45°,只能用两个 45 ° 45° 45° 夹角构成一个等腰直角三角形
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t=1;
const int maxn=200005;
pair<bool,bool> g[maxn];
void check(int i){
if(g[i].first&&g[i-1].second&&g[i-2].first){
ans++;
}
if(g[i].second&&g[i-1].first&&g[i-2].second){
ans++;
}
}
void solve(){
memset(g,0,sizeof(g));
int n;
cin>>n;
for(int i=1;i<=n;i++){
int ai,ki;
cin>>ai>>ki;
if(ki==0){
g[ai].first=true;
}else{
g[ai].second=true;
}
}
int ans=0;
for(int i=0;i<=n;i++){
if(g[i].first&&g[i].second){
ans+=n-2;
}
}
for(int i=2;i<=n;i++){
check(i);
}
cout<<ans<<endl;
}
signed main(){
cin>>t;
while(t--){
solve();
}
return 0;
}
E. Klee’s SUPER DUPER LARGE Array!!!
题意
给你一个首项为 k k k,长度为 n n n,公差为 1 1 1 的等差数列,即 [ k , k + 1 , . . . , k + n − 1 ] [k,k+1,\ ...\ ,k+n-1] [k,k+1, ... ,k+n−1]
找到一个 i ( 1 ≤ i ≤ n ) i\ (1\le i \le n) i (1≤i≤n),使得 ∣ a 1 + a 2 + . . . + a i − a i + 1 − . . . − a n ∣ \displaystyle |a_1+a_2+\ ...\ +a_i−a_{i+1}-\ ...\ -a_n| ∣a1+a2+ ... +ai−ai+1− ... −an∣ 最小
思路
二分找到最大的 p o s pos pos 使得 ∑ i = 1 p o s a i ≤ ∑ i = p o s + 1 n a i \displaystyle \sum_{i=1}^{pos} a_i \le \sum_{i=pos+1}^n a_i i=1∑posai≤i=pos+1∑nai(利用等差数列公式 ( 首项 + 末项 ) ∗ 项数 2 \displaystyle \frac{(首项+末项)*项数}{2} 2(首项+末项)∗项数 求和),比较一下 p o s pos pos 和 p o s + 1 pos+1 pos+1 哪个更优后输出
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t=1;
int n,k;
bool check(int i){
int l=k,r=k+n-1;
int preSum=(l+i)*(i-l+1)/2;
i++;
int sufSum=(i+r)*(r-i+1)/2;
if(preSum>sufSum){
return true;
}
return false;
}
void solve(){
cin>>n>>k;
int L=k,R=k+n-1; //最原始的左端点和右端点
int l=k,r=k+n-1;
while(l<r){
int mid=(l+r+1)/2;
if(check(mid)){
r=mid-1;
}else{
l=mid;
}
}
int mn=abs((L+l)*(l-L+1)/2-(l+1+R)*(R-l)/2);
l++;
mn=min(mn,abs((L+l)*(l-L+1)/2-(l+R+1)*(R-l)/2));
cout<<mn<<endl;
}
signed main(){
cin>>t;
while(t--){
solve();
}
return 0;
}
F. Firefly’s Queries
题意
给你一个数组 c c c,定义 x 反转 x \ 反转 x 反转 为 f ( x ) f(x) f(x): c x , c x + 1 , . . . , c n , c 1 , c 2 , . . . , c x − 1 c_{x},c_{x+1}, \ ... \ , c_n,c_1,c_2, \ ... \ , c_{x-1} cx,cx+1, ... ,cn,c1,c2, ... ,cx−1
b b b 数组: f ( 1 ) + f ( 2 ) + . . . + f ( n ) f(1)+f(2)+\ ... \ +f(n) f(1)+f(2)+ ... +f(n),加号代表把所有数组拼接在一起
共 q q q 次询问,每次给你 l , r l,r l,r,求 ∑ i = l r b i \displaystyle \sum_{i=l}^r b_i i=l∑rbi 的值
思路
把这个数组复制 1 1 1 遍加在最后,做一个前缀和,把整段的直接加上总和,零散的用前缀和数组加一下就可以了。
说多了有点废话还可能听不懂,直接看代码吧
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t=1;
const int maxn=200005;
int v[maxn];
int sum[2*maxn];
void solve(){
memset(v,0,sizeof(v));
memset(sum,0,sizeof(sum));
int n,q;
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>v[i];
sum[i]=sum[i-1]+v[i];
}
for(int i=n+1;i<=2*n;i++){
sum[i]=sum[i-1]+v[i-n];
}
while(q--){
int l,r;
int ans=0;
cin>>l>>r;
int posl=(l-1)%n+1,posr=(r-1)%n+1;
int numl=(l+n-1)/n,numr=(r+n-1)/n;
//posl,numl 代表 l 是第几组的第几个 posr,numr同理
ans=(numr-1-numl)*sum[n];
ans+=(sum[numr+posr-1]-sum[numr-1]);
ans+=(sum[numl+n-1]-sum[numl+posl-2]);
cout<<ans<<endl;
}
}
signed main(){
cin>>t;
while(t--){
solve();
}
return 0;
}