一起来做题~欢乐赛1

A 可以用map离散化

#include<bits/stdc++.h>
using namespace std;
int const N=2e5+7;
int t,n,m;
map<int,int>pos,cnt;  //可以用map离散化 //记录在数轴的位置并映射出它的值 
map<int,int>::iterator it; 
int main(){
    cin >> t;
    while(t--){
        cin >> n >> m;
        pos.clear();cnt.clear();
        for(int i=1;i<=n;++i){
            int a;cin >> a; 
            pos[a]=1;cnt[a]++;
        }
        for(int i=1;i<=m;++i){
            int a;cin >> a;
            pos[a]=0;cnt[a]=0;
        }
        int ans=0,sum=0;
        for(it=pos.begin();it!=pos.end();++it){
            if(it->second) sum+=cnt[it->first];
            else sum=0;
            ans=max(ans,sum);
        }
        if(ans) cout << ans << "\n";
        else cout << "Impossible\n"; 
    }
    return 0;
}

B 按灯题

尝试着分析(画一画,举例子)可以发现是按灯题的模型
第一个确定了,放法就确定了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int const N=1e4+7;
int n;
int a[N],l[N];
int pan(){
    for(int i=2;i<=n;++i){
        l[i]=a[i-1]-l[i-1]-l[i-2];
        if(l[i]<0||l[i]>1) return 0;
    }
    if(l[n]+l[n-1]!=a[n]) return 0;
    return 1;
} 
int main(){
    cin >> n;
    for(int i=1;i<=n;++i){
        cin >> a[i];
    }
    int cnt=0;
    l[1]=1;
    if(pan()) cnt++;
    l[1]=0;
    if(pan()) cnt++;
    cout << cnt;
    return 0;
}

C 提前操作和反向操作

发功后对前面的无影响,对后面的有影响,所以可以让其全部发完功再操作
操作可以从后往前

看到区间修改就要反映过来(差分前缀和、线段树)
特别是看到区间相对大小的变化,要反映过来是差分

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int const N=5e4+7;
int t,n,m;
int a[N],b[N],sex[N];
int main(){
    cin >> t;
    while(t--){
        cin >> n >> m;
        for(int i=1;i<=n;++i){
            cin >> sex[i] >> a[i];
            b[i]=a[i]-a[i-1];
        }
        for(int i=1;i<=m;++i) {
            int x;cin >> x;
            b[1]+=1;b[x+1]-=1;
        }
        for(int i=1;i<=n;++i) b[i]+=b[i-1];
        int maxn[2]={0,0},cnt=0;
        for(int i=n;i>=1;--i){
            if(b[i]>=maxn[sex[i]^1]) cnt++;
            maxn[sex[i]]=max(maxn[sex[i]],b[i]);
        }
        cout << cnt << "\n";
    }
    return 0;
}

D 记搜写dp

背包也是线性dp,想到可以由前面覆盖(转移),而无背包的形,要反映过来是线性dp

求分数,f肯定表示分数,而其表示的搜索状态一般为题目所给的条件

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int const N=357;
int n,m,op[6];
int a[N],f[47][47][47][47];
int dfs(int i,int j,int k,int l){
    if(i<0||j<0||k<0||l<0) return 0;
    if(f[i][j][k][l]!=0) return f[i][j][k][l];
    f[i][j][k][l]=max( max(dfs(i-1,j,k,l),dfs(i,j-1,k,l)),
                       max(dfs(i,j,k-1,l),dfs(i,j,k,l-1)) )
                  + a[1+i+2*j+3*k+4*l];  
    return f[i][j][k][l];
}
int main(){
    cin >> n >> m;
    for(int i=1;i<=n;++i) cin >> a[i];
    for(int i=1;i<=m;++i) {
        int x;cin >> x;
        op[x]++;
    }
    int ans=0;
    ans=dfs(op[1],op[2],op[3],op[4]);
    cout << ans;
    return 0;
}

E 用倍增预处理

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int const N=1e6+7;
int n,m,k;
ll a[N];
ll f[N][24];
int pan(int l,int r){
    int ans=0;
    for(int j=20;j>=0;--j){
        if(f[l][j]<=r){
            ans+=(1<<j);
            l=f[l][j];
        }
    }
    //if(f[l][0]==l&&a[l]>k) return 0;
    if(f[l][0]<=r) return 0;
    return ans+1;
}
int main(){
    cin >> n >> m >> k;
    for(int i=1;i<=n;++i){
        cin >> a[i];
    }
    for(int j=0;j<=20;++j){    
        for(int i=1;i<=n+1;++i){  //注意这里到n+1
            f[i][j]=n+1;    //初始化
        }
    }
    ll sum=0;
    for(int i=1,j=0;i<=n;++i){
        while(j<=n&&sum<=k) sum+=a[++j];
        f[i][0]=j;   //初始化
        sum-=a[i];
    }
    for(int j=1;j<=20;++j){
        for(int i=1;i<=n;++i){
            f[i][j]=f[f[i][j-1]][j-1];
        }
    }
    int l,r;
    for(int i=1;i<=m;++i){
        cin >> l >> r;
        int ans=0;
        ans=pan(l,r);
        if(ans) cout << ans << "\n";
        else cout << "Chtholly\n";
    }
    return 0;
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务