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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

posted @ 2023-05-11 21:30  bible_w  阅读(45)  评论(0编辑  收藏  举报