26寒假营第一场.pdf

A:2.4

B:

思路或者想法:

已知小红的卡牌排列,想要得到小苯的卡牌排列

在最高分数的情况下得到有多少种排列方式

猜测题型:组合数学,单调队列,单调栈,优先队列,贪心?

样例

4
1 8 7 2
3 6 4 5

如果我们将小的数字放到前面,比如1 2 7 8

那么小红将得到4分,小苯0分,故该思路不对

相反,我们将大的数字放到前面进行消耗,那么我们最高可以获得2分

比如 7 8 1 2

7和8移除之后,1,2不会被消耗,只有两分,再对其进行排列组合

这也是一个问题:因为对排列组合的学习理解不够深厚

所以思路便是将小苯的排列进行从大到小排序,尝试得到一个结果

但还需在某个节点进行思考,怎样得到更多的结果

C:

已AC,以下为核心代码

void solve(){
    int n;cin>>n;
    int tmp,maxn=-1;
    vector<int>vec;
    for(int i=0;i<n;i++){
        cin>>tmp;
        vec.push_back(tmp);
        maxn=max(tmp,maxn);
    }
    cout<<maxn*(n-2)+vec[0]+vec[n-1]<<endl;
}

希望数组中的所有数字总和尽可能大,那最好的一种情况就是将数组中的数字全部换为数组中最大的数字,但是要注意一个点,就是题中说选择下标,是开区间,也就是说可能开头和结尾处如果不是最大值那么也不能改变,需要分类讨论

答案的最大值就是maxn*(n-2)+vec[0]+vec[n-1]

E:

已AC,以下为核心代码

void solve(){
    int n,k;cin>>n>>k;
    vector<int>vec(n+2);
    for(int i=1;i<=n;i++){
        cin>>vec[i];
    }
    vec[n+1]=k;
    vector<int>dt(n+2);
    for(int i=1;i<=n+1;i++){
        if(i==1){
            dt[i]=vec[vec.size()-1]+vec[1];
            continue;
        }
        dt[i]=vec[i]+vec[i-1];
    }
    sort(dt.begin()+1,dt.end());
//     for(int i=1;i<dt.size();i++){
//         cout<<dt[i]<<' ';
//     }
//     cout<<endl;
    cout<<dt[n+1]<<endl;
}

从题目中就不难得出,该万能方块从左侧插入然后从右侧挤出一个新的万能方块

这其实就是队列的一种思想,先进先出思想,当然,本题我不打算使用队列来写,

用数组模拟队列足矣。

思路:

将万能方块也放入数组中,充当队列中的一员,那么我们要得出的就是一个循环队列中,求所有相邻两项和的最大值

a1,a2,a3,k s=a1+k

k,a1,a2,a3 s=k+a3

a3,k,a1,a2 s=a3+a2

a2,a3,k,a1 s=a2+a1

将这些s存入一个数组,用sort排序即可

D:

该题有了大概思路,不过未能实现

思路的核心代码

void solve(){
    int n,k;cin>>n>>k;
    vector<int>vec(n+1);
    int start=1;bool st=false;
    
    int numwhite=0;
    for(int i=1;i<=n;i++){
        cin>>vec[i];
        if(vec[i]!=0&&st==false){
            start=i;st=true;
        }
        
        if(vec[i]>0) numwhite++;
    }
    
    if(k>=numwhite){
        cout<<0<<endl;
        return;
    }
    
    int sec=1;//未定义
    
    k-=1;
    while(1){
        int next=vec[start]+start;
        start=next;
        if(next>=n){
            break;
        }
        if(vec[next]==0){
            if(k<0){
                cout<<-1<<endl;
                return;
            }
            for(int i=next;i<=n;i++){
                if(vec[i]!=0){
                    next=i;
                    k-=1;
                    break;
                }
            }
        }
        cout<<sec<<" "<<next<<endl;
        sec++;
        
    }
    cout<<sec<<endl;
}

数字序列,每个元素都有一个颜色,ai>0即白色,ai=0即黑色

ai所对应的值表明可以穿透多少色块

比如2 0 1 0 2 0 0 1

第一个2可以穿透第一个0直接到达1的位置将其染红

2 0 1 0 2 0 0 1

但是第一个1不能穿透0使后面的2染红

那么就要利用到k,即小苯开始时至多使k个白色元素染红(特判,如果白色元素数量numwhite小于等于k,那么我们直接一开始把所有白色元素染红即可,花费0秒),每次遇到黑色元素,那么我们从这里开始就穿过去直到找到第一个不为0的数字,将其染红,花费一次k,即k--,一直搜寻到最后一个元素

这里使用了一种迭代的方法(感觉很像动态规划,不过对于动态规划的理解还需再深入),就是找到序列中第一个不为0的数字其下标作为start,然后往后延申,下一个下标next就应该是vec[start]+start,就是start表示现在位置,vec[start]表示向后移动的位移,综合得出下一个目标移动位置,然后将该坐标点作为一个新的start,即start=next,由此逐步推进

但是这里遇到的问题是对于sec,现在要解决的问题就是穿透过去之后,k-=1,相对应的sec也要变为0,因为如果要消耗k,那么就说明这个染红的点是从0秒得到的

所以,我们就要记录所有秒数,然后求得一个最大的秒数,这样就可以确保所有白色元素被染红

如果染到后面发现k<0,那么就说明不能染完所有,输出-1

F:2.4

G:2.4

H:2.4

I:2.4

J:2.4

K:

已AC,以下为核心代码

void solve(){
    int n;cin>>n;
    if(n==1){
        cout<<"YES"<<endl;
        cout<<1<<endl;
    }else if(n==3){
        cout<<"YES"<<endl;
        cout<<"1 2 3"<<endl;
    }else{
        cout<<"NO"<<endl;
    }
}

思维题,思路感觉很简单,因为我也没推导出相应公式直接套的

如果数组长为1或者3,才有可能出现以下公式

a1*a2*a3......*an=a1+a2+a3+......+an;

数组长为1,那么不用推了

数组长为3,a1,a2,a3分别为1,2,3,这样才有可能

感觉数组再长都不会改变NO的结果了

L:

已AC,以下为核心代码

void solve(){
    int n;
    cin>>n;
    n%=10;
    if(n==1||n==3||n==7||n==9) cout<<10<<endl;
    else if(n==2||n==8||n==4||n==6) cout<<5<<endl;
    else if(n==5) cout<<2<<endl;
    else if(n==0) cout<<1<<endl;
}

如果希望n的个位为0,那么只要从它的个位入手即可

对n的个位分类讨论即可