2023 SMU RoboCom-CAIP 选拔赛
2023 SMU RoboCom-CAIP 选拔赛
A - 小斧头
思路:
70分
由于区间范围越大,最大值越大,st表存区间最大值,枚举bi的值作为[l,r]内最大值,可用二分求出l,r的范围(左边求小于bi,右边求小于等于bi,这样可以得到所有的可能)
#include<bits/stdc++.h> using namespace std; typedef pair<int,int>PII; typedef pair<string,int>PSI; const int N=1e6+5,INF=0x3f3f3f3f,Mod=998244353; const double eps=1e-6; typedef long long ll; #define int long long int32_t main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int n; cin>>n; vector<int>lg(n+1),a(n+1),b(n+1); for(int i=2;i<=n;++i)lg[i]=lg[i>>1]+1; vector<vector<int>>f(n+1,vector<int>(lg[n]+1,0)); for(int i=1;i<=n;++i)cin>>a[i]; for(int i=1;i<=n;++i){ cin>>b[i]; f[i][0]=max(a[i],b[i]); } for(int i=1;i<=lg[n];++i){ for(int j=1;j+(1<<i)-1<=n;++j){ f[j][i]=max(f[j][i-1],f[j+(1<<(i-1))][i-1]); } } auto search=[f,lg](int l,int r){ if(r<l)return 0ll; int s=lg[r-l+1]; return max(f[l][s],f[r-(1<<s)+1][s]); }; int res=0; for(int i=1,l,r,L,R,m;i<=n;++i){ L=R=i; l=1,r=i-1; while(l<=r){ m=(l+r)>>1; if(search(m,i-1)<b[i])L=m,r=m-1; else l=m+1; } l=i+1,r=n; while(l<=r){ m=(l+r)>>1; if(search(i+1,m)<=b[i])R=m,l=m+1; else r=m-1; } if(search(L,R)>b[i])continue; L=i-L+1,R=R-i+1; res+=L*R; } cout<<res; return 0; }
100分
dp,f[i]表示以i为右边界的所有个数,f[i] = f[j] + (b[i]>=a[i]) * (i-j),j表示i前的最近的max(a[j],b[j])大于b[i]的位置
#include<bits/stdc++.h> using namespace std; typedef pair<int,int>PII; typedef pair<string,int>PSI; const int N=1500+5,INF=0x3f3f3f3f,Mod=1e6; const double eps=1e-6; typedef long long ll; ll n,res; int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n; vector<int>a(n+1),b(n+1),c(n+1); vector<ll>f(n+1); stack<int>aa,bb; for(int i=1;i<=n;++i)cin>>a[i]; for(int i=1;i<=n;++i)cin>>b[i],c[i]=max(a[i],b[i]); for(int i=1,p;i<=n;++i){ while(!aa.empty()&&a[i]>c[aa.top()])aa.pop(); while(!bb.empty()&&b[i]>c[bb.top()])bb.pop(); if(b[i]>=a[i]){ if(bb.empty())p=0; else p=bb.top(); f[i]=f[p]+(i-p); } else{ if(aa.empty())p=0; else p=aa.top(); f[i]=f[p]; } res+=f[i]; aa.push(i),bb.push(i); } cout<<res; return 0; }
B - 能不能整除?
40分
统计每种ai/aj的值的个数
100分
还是统计值的个数,对于ai/aj如果ai确定了,值的种数最多2√ai,再求aj的范围即可;所以枚举ai的值,再枚举ai/aj的值,可以用前缀和统计符合范围的aj的个数
#include<bits/stdc++.h> using namespace std; typedef pair<int,int>PII; typedef pair<string,int>PSI; const int N=1e5+5,INF=0x3f3f3f3f,Mod=998244353; const double eps=1e-6; //typedef long long ll; #define int long long int n,T,mod; int32_t main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n>>T>>mod; vector<int>a(n); for(auto &i:a)cin>>i; int m=*max_element(a.begin(),a.end()); vector<int>pre(m+1); for(int i:a)pre[i]++; for(int i=1;i<=m;++i)pre[i]+=pre[i-1]; vector<int>cnt(T+1); auto query=[pre](int l,int r){ if(r<l)return 0ll; if(l==0)return pre[r]; return pre[r]-pre[l-1]; }; for(int i=1,l,r;i<=m;++i){ if(query(i,i)==0)continue; for(int j=0;j<=T&&j*i<=m;++j){ l=i*j,r=min(m,l+i-1); cnt[j]=(cnt[j]+query(i,i)*query(l,r))%mod; } } int res=0; for(int i=0;i<=T;++i){ if(cnt[i]==0||cnt[T-i]==0)continue; res=(res+cnt[i]*cnt[T-i]%mod)%mod; } cout<<res; return 0; }
C - 又是一道构造题
思路:矩阵第i行第j列的数一定是a[i]和b[j]的因子,每次求下gcd(a[i],b[j])即可
#include<bits/stdc++.h> using namespace std; typedef pair<int,int>PII; typedef pair<string,int>PSI; const int N=2e3+5,INF=0x3f3f3f3f,Mod=998244353; const double eps=1e-6; typedef long long ll; int t,n,m,a[N],b[N],s[N][N]; int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>t; while(t--){ cin>>n>>m; for(int i=1;i<=n;++i)cin>>a[i]; for(int i=1;i<=m;++i)cin>>b[i]; for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j){ int c=__gcd(a[i],b[j]); s[i][j]=c; a[i]/=c,b[j]/=c; } } bool ok=true; for(int i=1;i<=n;++i)if(a[i]!=1)ok=false; if(ok)for(int i=1;i<=m;++i)if(b[i]!=1)ok=false; if(ok){ for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j){ cout<<s[i][j]<<' '; }cout<<'\n'; } } else cout<<"-1\n"; } return 0; }