Codeforces Round 971 (Div. 4) A-F 题解

博主Rating现在才 1543 1543 1543,仅代表个人观点,如有不同的见解,欢迎在评论区提出

A. Minimize!

题意

给你 a a a b b b,找到一个 c   ( a ≤ c ≤ b ) c \ (a\le c\le b) c (acb),使得 ( c − a ) + ( b − c ) (c-a)+(b-c) (ca)+(bc) 最小

思路

原式可化简为 c − a + b − c = − a + b = b − a c-a+b-c=-a+b=b-a ca+bc=a+b=ba,所以直接输出 b − a b-a ba

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 (ni1),找到 # 的位置(从最后一行开始

思路

直接按题意模拟

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 (1dk) 步。第奇数次往右跳,即移动到 ( 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+k1) / k2if((x+k1)/k>(y+k1)/k)):        right=(x+k1)/k21else:        right=(x+k1)/k2
注:此处 ( a + b − 1 ) / b (a+b-1)/b (a+b1)/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=xk1 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° 夹角构成一个等腰直角三角形

pAZer24.jpg

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+n1]

找到一个 i   ( 1 ≤ i ≤ n ) i\ (1\le i \le n) i (1in),使得 ∣ 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+ ... +aiai+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=1posaii=pos+1nai(利用等差数列公式 ( 首项 + 末项 ) ∗ 项数 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, ... ,cx1

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=lrbi 的值

思路

把这个数组复制 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;
}
  • 22
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值