4.8 蓝桥杯备赛


题目来源:牛客竞赛

1、暧昧(计数问题,概率论老师给讲明白了)

在这里插入图片描述
在这里插入图片描述

知识点一、快速幂

pow(a,b)的时间复杂度是O(b),即每次乘b,都得再运算一次。
而快速幂算法的时间复杂度是O(logb),可以有效减少运行计算机计算的次数

在这里插入图片描述
在这里插入图片描述

伪代码

fun(a,b)
sum=1
while b!=0
if(n%2==1)
sum=sum*a
a=a*a
b=n/2

在这里插入图片描述

快速幂的代码:

const long long m=1e9+7;
long long quickpow(long long a,long long b)
{
    long long sum=1;
    while(b)
    {
        if(b&1)//与运算,可判断奇偶,详细见注释
           sum=sum*a%m;//取模运算
        a=a*a%m;
        b>>=1;//位运算,右移,相当于除以2
    }
    return sum;
}

知识点二、位运算

左移1位相当于乘以2,左移运算符“<<;
右移1位相当于除以2,右移运算符“>>;

知识点三、核心思想:计数

首先,根据“权值”的定义,既包含0也包含1的一串数字,权值+1
则n位数中,先确定1的位置,有n种取法
再确定0的位置,有(n-1)种取法
最后,剩下的(n-2)个位置,取0还是1都可以,每个位置有2种取法,有(n-2)个位置,则有2^(n-2)种取法
则最后输出时就是n*(n-1)*2^(n-2)
 
最后要注意一下取模问题

(n*(n-1)*qpow(2,n-2))%mod)

AC 代码

#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
 
ll qpow(ll a,ll b)//快速幂,时间复杂度较低
{
    ll sum=1;
    while(b)
    {
        if(b&1)//与运算,可判断奇偶,详细见注释
          sum=sum*a%mod;//取模运算
        a=a*a%mod;
        b>>=1;//位运算,右移,相当于除以2
    }
    return sum;
}
 
int main()
{
    ll n;
    cin>>n;
    if(n==1) //注意分析特殊情况,因为这一个特殊情况卡样例卡了好久
    	puts("0");
    else
    	cout<<((n*(n-1)%mod)*qpow(2,n-2))%mod<<endl;
    return 0;
}

python3代码

Python不愧以简洁出名,3句解决了C++十几行代码

# pow(x,y,z):表示x的y次幂后除以z的余数
#注意是长度为n,不是数字为n
n=int(input())
mod=10**9+7
print(n*(n-1)*pow(2,n-2,mod)%mod)

2、悸动的距离

在这里插入图片描述
链接:https://ac.nowcoder.com/acm/problem/248434
来源:牛客网

示例1

输入

1 1 -1 -1
输出

1
说明
线段AB和两个坐标轴的交点重合了,因此只有一个交点。

示例2

输入

3 0 0 3
输出

2
说明
端点在坐标轴上也视为有交点

示例3

输入

2 -1 2 3
输出

1

示例4

输入

-9 2 -2 9 输出 0

思路

用坐标乘积的正负来表示是否有交点,注意特殊情况原点

AC代码

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

int main()
{
    int xa,ya,xb,yb;
    
    cin>>xa>>ya>>xb>>yb;
     
    int cnt=0;
    if(xa*xb<=0)//记得有等于0,因为有可能在坐标轴上
        cnt++;
    if(ya*yb<=0)
        cnt++;
    if(cnt==2&&xa*yb==xb*ya)//经过原点
        cnt--;
    cout<<cnt<<endl;
    return 0;
}

3、暖色记忆(双指针也没太熟练,需要多练练)

在这里插入图片描述
在这里插入图片描述

知识点:双指针

AC 代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N],n;

int main()
{
    cin>>n;//气死,忘记输入n了,我说怎么没有输出
    for(int i=0;i<n;i++)
        cin>>a[i];
    sort(a,a+n);//升序排列后,隔一个数删除一个
    long long res = 0;
    
    //双指针
    for(int i = n - 1, k = 2; i >= n / 2; i --, k *= 2)
        if(k >= a[i])  
            break;
        else    
            res += a[i] / k;
    cout<<res<<endl;
    
    return 0;
}

4、回眸

在这里插入图片描述
在这里插入图片描述

知识点:整型转浮点数*1.0、注意保留小数的位数

AC代码

#include<iostream>
using namespace std;

int main()
{
    double a,v1,v2,v11;
    cin>>a>>v1>>v2>>v11;
    
    double t1,t2;
    
    //注意要a*1.0,不然浮点数不能直接相除
    t1=a*1.0/(v1+v2);//相遇的时间
    t2=(a-t1*v1)*1.0/v11;
    
    //注意这句话://表示了需要输出大于等于5位的小数
    //如果你的答案和标准答案的相对误差不超过...则认为你的答案正确
    printf("%.5lf\n",t1+t2);
    return 0;
}

5、风间

在这里插入图片描述
输入

4
3
1 3 5
5 3 1
4
1 3 5 7
2 4 6 8
5
1 2 3 4 5
5 4 3 2 1
4
1 1 4 5
5 4 1 1

输出:

4
-1
10
-1

在这里插入图片描述

模拟第一组样例
1 3 5
5 3 1
 
x=1-5=-4
5 -1 5
5 3 1
 
x=-1-3=-4
5 3 1
5 3 1

思路:

先逐个对比ai和bi,差值为想,则需要操作x/2次,
让当前的ai和bi相等,如果差值为偶数,则可以变为一样,如果为奇数则不能
再管后面的ai+1和bi+1,用上面同样的方法让其相等,直到最后

注意:labs是abs函数的long int版

#include<iostream>
#include<cmath>
using namespace std;
const int N=2e5+10;

long long a[N],b[N];

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=0;i<n;i++)
            cin>>a[i];
        for(int i=0;i<n;i++)
            cin>>b[i];
        
        int flag=0;
        long long sum=0;
        for(int i=0;i<n;i++)
        {
            long long x=a[i]-b[i];
            if(labs(x)%2==1)//差值为奇数
            {
                //则整个序列都不能变成相同数字
                flag=1;
                break;
            }
            else//差值为偶数
            {
            //一定要注意,x可以为负数,当a[i]<b[i]的时候,x为负数,这种时候,a[i+1]实际在减
                a[i+1]+=x;//记得后一位数字要加上相应的数字
                sum+=labs(x)/2;
            }        
        }
        
        //注意条件:每位数字的差值都为偶数,且最后一位相同
        if(flag==0&&a[n-1]==b[n-1])
            cout<<sum<<endl;
        else     
            cout<<-1<<endl;      
    }
    return 0;
}

6、惊鸿

在这里插入图片描述
在这里插入图片描述

知识点:位运算

位运算规则:两个二进制操作数对应位只要有一个为1 结果位 就为1,其余情况为0
例:2 | 4 即 00000010 | 00000100 = 00000110 ,所以2 | 4的值为 6
egg:2^29=536870912 //9位数 int型是10位数,不会超时

#include<iostream>
using namespace std;

int main()
{
    int t;
    cin>>t;
    
    int a,b,c,d;
    
    while(t--)
    {
        cin>>a>>b>>c>>d;
        cout<<4*(a|b|c|d)<<endl;
    }
    return 0;
}

7、Alice and Bob(博弈论,老早之前的题,忘记了)

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

AC代码

/*
Alice 和 Bob 正在玩一个游戏,
双方都很聪明。游戏是这样的,给出一个正整数 n,然后每次轮流操作,
每次操作需要将数 n 除以  a^k
Alice 先手,谁先将数 n 变为 1 则谁输。
*/

/*
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;
const LL N=200200,M=2002;
*/
#include<iostream>
using namespace std;
typedef long long LL;
const LL N=200200;

int main()
{
    /*
	cin.tie(0);
	cout.tie(0);

	ios::sync_with_stdio(false);
*/
    
	int T=1;
	//cin>>T;
	while(T--)
	{
		LL n;
		cin>>n;
		LL sum=0,flag=0;
		
		//找到a和k
		for(LL a=2; a<=n/a; a++)
		{
			if(n%a==0)//不是素数 
			{
				int k=0;//记录个数
				
				while(n%a==0)
				{
					k++;
					n/=a;
				}
				if(k>1)
					flag=1;
				sum^=k;//异或的作用:相同为0,不同为1 
			}
		}
		if(n>1)
			sum^=1;
			
		//反尼姆博弈的先手必胜条件有两个
		//异或和为0, 所有数等于 1
		//异或和不为0 ,至少一个数大于1
		if((!flag&&!sum)||(flag&&sum))
			cout<<"Alice win"<<endl;//先手胜 
		else
			cout<<"Bob win"<<endl;//后手胜 
	}
	return 0;
}

/*
如果n是个素数(n=3),因子的次方k=1,flag=0,则第一次Alice就把n变成1,alice输,bob赢

如果n不是个素数(n=6),因子的次方k=1,flag=0,则第一次之后,n就成了素数,alice赢,bob输

如果n不是个素数(n=12),但因子的次方>1,flag=1,则第一次Alice变过之后,n就成了素数,alice赢,bob输
 */

7、画牌河(换行)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

AC代码

#include<iostream>
using namespace std;
int a[100];

int main()
{
    int x;
    cin>>x;//放置的牌数
    for(int i=1;i<=x;i++)
        a[i]=1;
    
    for(int i=1;i<=18;i++)
    {
        cout<<a[i];
        if(i%6==0)//每隔6个数一换行
            cout<<endl;
    }
     return 0;   
}

8、构造有向无环图(acwing)

思路:拓扑排序

在这里插入图片描述
在这里插入图片描述

先考虑有向边,
若有环,则一定无解
若无环,则一定有解,用拓扑排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值