牛客多校第一场
题目
题解
数学题比较多,而我数学又比较菜,结果就是自闭了一下午。叉姐的讲解听了跟没听一样!!!
A
题意
若两个数组任意区间的最小值的位置相同,则称这两个数组等价。给定两个数组,求等价的前缀数组最大长度。
5
3 1 5 2 4
5 2 4 3 1
4
分析
显然答案具有单调性,可以二分答案。【1,n】
接下来考虑如何判断两个数组是否等价。利用ST算法预处理得到任意区间的最小值下标,若两个数组最小值下标不相同,则一定不等价;若相同,则包含该下标的所有区间的最小值下标均相同,因此以此下标为界分割区间递归判断。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10,inf=0x3f3f3f3f;
int n;
int a[N],b[N],ma[N][25],mb[N][25];
void prec(int f[][25],int x[]){
for(int i=1;i<=n;i++){
f[i][0]=i;
}
for(int j=1;j<25;j++){
for(int i=1;(i+(1<<j)-1)<=n;i++){
if(x[f[i][j-1]]<x[f[i+(1<<(j-1))][j-1]]){
f[i][j]=f[i][j-1];
}else{
f[i][j]=f[i+(1<<(j-1))][j-1];
}
}
}
}
int query(int f[][25],int x[],int l,int r){
int k=int(log2(r-l+1));
if(x[f[l][k]]<x[f[r-(1<<k)+1][k]])
return f[l][k];
else
return f[r-(1<<k)+1][k];
}
bool exam(int l,int r){
if(l>=r)return true;
int mina=query(ma,a,l,r);
int minb=query(mb,b,l,r);
if(mina==minb){
return exam(l,mina-1)&&exam(mina+1,r);
}else{
return false;
}
}
bool check(int ans){
return exam(1,ans);
}
int main(){
//cout<<log2(4)<<endl;
while(~scanf("%d",&n)){
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
for(int i=1;i<=n;++i)scanf("%d",&b[i]);
prec(ma,a);
prec(mb,b);
int left=1,right=n,ans;
while(left<=right){
int mid=(left+right)>>1;
//printf("left=%d,right=%d\n",left,right);
//printf("check(%d)=%d\n",mid,check(mid));
if(check(mid)){
ans=mid;
left=mid+1;
}else{
right=mid-1;
}
}
printf("%d\n",ans);
}
} B
题意
给定,求
分析
显然要进行裂项,假设:
右端通分可得:
代入n=2,n=3,找规律,再加上一点想象力,推测:
将上式代入积分,可得:
其他注意点:
- 取模需要求逆元(可用费马小定理)
- 注意不要出现负数取模
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=1e3+5;
ll n,a[N];
ll qpow(ll x,ll y){
ll ans=1;
while(y){
if(y&1)
ans=(ans*x)%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
ll inv(ll a){
return qpow(a,mod-2);
}
int main(){
while(~scanf("%lld",&n)){
ll ans=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;i++){
ll temp=2*a[i];
for(int j=1;j<=n;j++){
if(j==i)continue;
temp=(temp*(a[j]*a[j]%mod-a[i]*a[i]%mod+mod))%mod;
}
ans=(ans+inv(temp))%mod;
}
printf("%lld\n",(ans+mod)%mod);
}
return 0;
} J
题意
比较x/a与y/b。
分析
考虑到数据范围,有如下几种做法:
- 转换为乘法,使用Python自带高精度
- 转换为乘法,使用GCC内置的
__int128 - 先比较商,再对分子求余,再转换成乘法比较
代码
Python自带高精度try: while True: x,a,y,b=map(int,input().split()) res=b*x-a*y if(res==0): print('=') elif(res>0): print('>') else: print('<') except: passGCC__int128#include <bits/stdc++.h> using namespace std; int main(){ long long x,a,y,b; while(cin>>x>>a>>y>>b){ __int128 res=(__int128)b*x-(__int128)a*y; if(res==0)putchar('='); else if(res<0)putchar('<'); else putchar('>'); putchar('\n'); } return 0; }先比较商#include <bits/stdc++.h> using namespace std; int main(){ long long x,a,y,b,p,q; while(cin>>x>>a>>y>>b){ p=x/a,q=y/b; if(p==q){ x%=a,y%=b; if(x*b==y*a)puts("="); else if(x*b<y*a)puts("<"); else puts(">"); }else if(p<q)puts("<"); else puts(">"); } }

京公网安备 11010502036488号