BUU round2 题解

round 2 题解

这次更多考验算法和编码能力。

题目难度
由易到难

  1. A < F < B
  2. D E C

A 三角形的类型 几何题 难度 1.5

有多种方法可以做这道题。
需要注意一些点。

  1. 三点成一条直线的情况
  2. 两个点重合时,三个点重合的情况。
  3. 注意精度问题。
  4. 如果采用求直线斜率,要注意不能除0。
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn = 1e5+5;
const int inf = 0x3f3f3f3f;

typedef long long ll;

double eps = 0.0001;
ll x1,y11,x2,y2,x3,y3;
double cal(double x1,double x2,double y11,double y2){
    return sqrt( (x2-x1)*(x2-x1)+(y2-y11)*(y2-y11) );
}
void solve(){
    scanf("%lld%lld%lld%lld%lld%lld",&x1,&y11,&x2,&y2,&x3,&y3);
    double l1 = cal(x1,x2,y11,y2);
    double l2 = cal(x1,x3,y11,y3);
    double l3 = cal(x3,x2,y3,y2);


    if(abs(l1)<eps||abs(l2)<eps||abs(l3)<eps){
        cout<<"No"<<endl;
        return ;
    }
    if(l1 == l2 && l2 == l3){
        cout<<"equilateral triangle"<<endl;
        return ;
    }
    if(l2 > l1 && l2 > l3) swap(l1,l2);
    if(l3 > l1 && l3 > l2) swap(l1,l3);
    
    //此时l1最大
    if(l2+l3 == l1){
    	cout<<"No"<<endl;
    	return ;
    }
    double ll = l2*l2 + l3*l3;
    l1 = l1*l1;
    if(abs(ll - l1) < eps){
        if(abs(l2-l3)<eps){
            cout<<"Isosceles Right Triangle"<<endl;
        }else
            cout<<"right triangle"<<endl;
    }else if(ll - l1 < eps){
        cout<<"obtuse triangle"<<endl;
    }else{
        cout<<"acute triangle"<<endl;
    }
}
int main(){

    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

B 字符串的秘密 字符串 + 前缀和模板 难度 2.0

用前缀和,把字母替换成对应的权值。

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e5;
typedef long long ll;
ll sum[N];
int main()
{
	int n,q;
	cin>>n>>q;
	getchar();
	for(int i = 1;i<=n;i++){
		char ch = getchar();
		if(ch == ' '){
			sum[i] = sum[i-1];
		}else{
			sum[i] = sum[i-1] + ch-'a'+1;
		}
	}
	for(int i = 1;i<=q;i++){
		ll l,r;
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",sum[r]-sum[l-1]);
	}
	return 0;
}

C 谁是博弈滴神 思维 博弈 难度2.5

每个人都要采取最优的策略,来保证自己最大概率获胜。
那么先行动的人就有优先选择权。

如果从必胜的角度不好考虑,可以从对方必败的角度考虑。
如果小w把石子分成两个一模一样的部分,这两部分不能相连。
那么无论小y怎么取A部分,小w只要模仿小y同样取B部分就可以保证必胜。

反之 如果小w无法把石子分成两个一模一样的部分,那么小y只需要用同样的策略就可以获胜。

小w的必胜态:
k >= 2 : 无论n怎么样,都能分成两部分一模一样。
n是奇数 : 只要n是奇数个,无论k怎么样,都能分成一模一样的两部分。

小y的必胜态:
k == 1 && n是偶数: 小w无论怎么取,都会留下一奇一偶两部分 ,(偶部分可能为0个,奇部分最少为1个)
对于奇部分,小y可以将其分成两部分一模一样的,这样奇数部分小y一定最后取完。
对于偶部分,留给小w先取,然后又回到了上面的情况。

#include <stdio.h>
int main()
{
    int n, k;
    scanf("%d %d",&n,&k);
    if(n == 0){
        printf("y yyds!\n");
    }
    else if(k == 
f("w yyds!\n");
        }
    }
    else{
        printf("w yyds!\n");
    }
    return  0;
}

D 搭积木 最长上升子序列 难度 2.0

求最长上升子序列。
答案是n-最长上升子序列的长度。
n方的dp做法和nlogn的二分做法都能过。

因为a可以改变为任意大于0的实数。
那么只要得出最长上升子序列后,其他数按照该上升序列构造一个满足严格单增的序列即可。

二分做法。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;

// O(nlogn)
const int N = 1e6+5;
ll b[N];
int main()
{
	int n;
	cin>>n;
	ll cnt = 1;
	for(int i = 1;i<=n;i++){
		ll x;
		scanf("%lld",&x);    
		ll id = lower_bound(b+1,b+cnt,x)-b;
		// cout<<id<<endl;
		b[id] = x;
		if(id == cnt) cnt++; 
	}
	// for(int i = 1;i < cnt;i++){
		// cout<<b[i]<<" ";
	// }
	cout<<n-cnt+1;
	return 0;
}

n方的DP做法

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;

const int N = 1e6+5;
ll a[N];
ll f[N];

//O(n*n)
int main()
{
	int n;
	cin>>n;
	for(int i = 1;i<=n;i++){
		scanf("%lld",&a[i]);    
	}
	
	ll maxlen = -1;
	for(int i = 1;i<=n;i++){
		ll now = 1;
		for(int j = i-1;j >= 1;j--){
		    if(a[j] < a[i]){
		    	now = max(now,f[j]+1);
		    }
		}
		f[i] = now;
		maxlen = max(maxlen,f[i]);
	}
	// for(int i = 1;i<=n;i++){
		// cout<<f[i]<<" "; 
	// }
	cout<<n-maxlen;
	return 0;
}

E 英雄联盟 多种做法 模拟 思维 难度2.0

有很多种做法:

  1. 模拟
  2. 差分
  3. https://www.luogu.com.cn/problem/solution/P1969

1. 模拟

模拟的做法:递归。

我们可以把加血变成从满血状态扣血。
每次技能的范围都尽可能地大。
那么就变成了求解每一个不包含0的区间[l,r]

求解lr区间,我们先找到区间的最小值。然后把区间里的所有元素都减去该最小值,得到被零划分成多个的子区间。

该区间的答案就是区间最小值 + 所有子区间的答案。

#include<iostream>
#include<cstdio>
using namespace std;

typedef long long ll;
const int N = 1e5+5;
const ll inf = 1e18;
ll a[N];
int n;
ll cal(int l,int r){
	if(l > r) return 0;
	if(l == r) {
		ll ans = a[l];
		a[l] = 0;
		return ans;
	}
	ll minn = inf;
	for(int i = l;i<=r;i++){
		minn = min(minn,a[i]);
	}
	int pre = l;
	ll ans = minn;
	for(int i = l;i <= r;i++){
		a[i] -= minn;
		if(a[i] == 0){
			ans += cal(pre,i-1);
			pre = i+1;
		}
	}
	if(a[r] != 0)
	    ans+=cal(pre,r);
	return ans;
}
int main()
{
	cin>>n;
	for(int i = 1;i <= n;i++){
		scanf("%lld",&a[i]);
	}	
	cout<<cal(1,n);
	return 0;
}

2. 差分

把序列分成(a1,…ai) (ai+1,…aj) … (ak,…an) 多个非递减序列。

然后把每段序列的最大值加起来 的 sum。
无论如何答案都不可能超过sum。

那么还能继续减少,即减去除了第一个序列外的最小值min。
因为我们可以提前先用所有大于min的元素减去这个最小值min。

#include<stdio.h>
int n;
int x;
int ans = 0;
int main()
{
	scanf("%d",&n);
	scanf("%d",&x);
	ans += x;
	int cur = x;
	for(int i = 1;i < n;i++){
		scanf("%d",&x);
		if(x>=cur){
			ans += (x - cur);
		}
	    cur = x;
	}
	
	printf("%d",ans);
	
	return 0;
}

F 试炼塔1.0 逆元 + 快速幂 难度1.5

主要考察逆元和快速幂(模板代码在题面)。
公式是
(1/q) 的n次方 乘 (n*(n+1))/2

对于求逆元,我们需要把分母全部求其对1e9的逆元。
然后分子乘上所有的逆元。

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
/*******快速幂********/
ll powerMod(ll x, ll n, ll m){ //求解 x的n次方 并求模于m

    if(n==0) return 1;
    ll res = 1;
    while (n > 0){
        if  (n & 1) //  判断是否为奇数,若是则true
            res = (res * x) % m;
        x = (x * x) % m;
        n >>= 1;    //  相当于n /= 2;
    }
    return res;
}

//求k ,k = b关于p的逆元
ll inv(ll b, ll mod)
{
    return powerMod(b,mod-2,mod); //powerMod为快速幂,函数定义在上面
}
int main()
{
	ll n,q;
	while(scanf("%lld%lld",&n,&q)!=EOF){
		ll inv2 = inv(2,mod)%mod;
		ll invq = inv(q,mod)%mod;
		ll ans = ( n*(n+1) ) % mod;
		ans = (ans*inv2)%mod;
		ans = (ans * powerMod(invq,n,mod))%mod;
		printf("%lld\n",ans);
	}
	return 0;
}

比赛中出现的点:

  1. 读入一行字符串(包括空格)时,需要用getline或者getchar()一个个字符读入。
  2. 除法一定记得要用逆元。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值