文章目录
题目来源:牛客竞赛
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)
思路:拓扑排序
先考虑有向边,
若有环,则一定无解
若无环,则一定有解,用拓扑排序