牛客小白月赛#56 A~F

牛客小白月赛#56

A.阿宁的柠檬

  • 题意

    • 甜度的分值范围为0a,酸度的分值范围为1b
    • 有n个柠檬,求最小分值和最大分值
  • 题解

    • 最小值为甜度取0,酸度取1,分值为0*n+1*n;最大值为甜度,酸度取a,b,分值为a*n+b*n
  • 代码

#include <iostream>

using namespace std;

int main() {
    long long a,b,n;//注意爆int
    cin>>a>>b>>n;
    cout<<n<<' '<<(a+b)*n<<'\n';
    
    return 0;
}

B.阿宁与猫咪

  • 题意

    • 给定值m;构造一个正整数数列,元素之和为m,且奇数位置之积 与 偶数位之积 的和最小
  • 题解

    • 猜测结论:构造的数列是m个1
    • 证明上述结论成立:全为1时,其奇数位积于偶数位积之和必然为2(m!=1时);其他的构造也就是要替换掉某些1变成不是1的元素,那么必然奇数位或者偶数位积>1,那么之和>2,所以可以证得,上述方案为最优方案
  • 代码

#include <iostream>

using namespace std;

int main() {
    int m;
    cin>>m;
    cout<<m<<'\n';
    for(int i=1;i<=m;i++) cout<<1<<' ';
    
    return 0;
}

C.阿宁吃粽子

  • 题意

    • n条带美味值粽子,总的美味值计算如下,安排n个粽子吃的顺序,使得总美味值最大
      W = ∑ k = 1 n a k × 2 k % 10 , k 为吃的次序 W=\sum_{k=1}^{n}a_k\times2^{k\%10},k为吃的次序 W=k=1nak×2k%10,k为吃的次序

    • 如果有多种符合要求的解,那么把美味值大的放到后面

  • 题解

    • 构造,按要求构造一个最大的排序。先把美味值排序,美味值越大的放在2次幂权值大的位置上,可以用二维vector记录权值k时有哪些位置,然后一次把排好序的粽子排放在位置上
    • 对于我来说,难点在代码实现上
  • 代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
const int N=2e5+10;

int n,a[N],ans[N];//记录美味值,记录答案
vector<int> b[12];//记录权值为0~9的位置有哪些

int main() {
    cin>>n;
    for(int i=1;i<=n;i++) {
        cin>>a[i];
        b[i%10].push_back(i);//初始化好对应权值的位置
    }
    sort(a+1,a+1+n);//排序
    
    for(int i=n;i;i--) {//贪心把美味值大的放在权值大的位置
        for(int j=9;j>=0;j--) {
            if(b[j].size()) {
                int x=b[j].back();//从大的位置开始放,满足题目要求
                b[j].pop_back();
                ans[x]=a[i];//每填一个就break去填下一个
                break;
            }
        }
    }
    
    for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
    puts("");
    
    return 0;
}

D.阿宁的质数

  • 题意

    • 询问q次,长度为n的数组中前x个数中没有出现的最小质数
  • 题解

    • 由题得,当a为n个从小到大的质数,那么对于任意一个询问,暴力寻找答案时,寻找复杂度最高。因为一旦a有不连续的质数,那么暴力寻找时就不需要从1到x,在x之前就找到没有出现的最小质数了。因此预处理出前2e5个质数就是极限的寻找范围了,同时应该用线性筛1~3e6左右个数才能筛出2e5个素数
    • 因为对于所有的位置的答案都是确定的,所以可以先预处理出每个位置的答案。因为查找的范围是一个从1开始的不断向后延展的区间,切寻找的是最小没出现的质数,所以可以利用双指针思维,指向答案的指针随着区间扩展时单调(不严格)递增的。
  • 代码

#include <iostream>

using namespace std;
const int N=2e5+10,M=3e6+10;//数组的大小,筛素数的范围

int n,q,a[N],ans[N];//存每个位置的答案

int cnt,primes[M];//筛素数
bool st[M];

bool vis[M];//找答案的辅助数组

void get_primes() {//线性筛素数
    for(int i=2;i<M;i++) {
        if(!st[i]) primes[cnt++]=i;
        for(int j=0;primes[j]<=M/i;j++) {
            st[primes[j]*i]=true;
            if(i%primes[j]==0) break;
        }
    }
}

int main() {
    get_primes();
    //cout<<cnt<<'\n';
    
    cin>>n>>q;
    for(int i=1;i<=n;i++) cin>>a[i];
    
    int p=0;//指向答案的指针
    for(int i=1;i<=n;i++) {//遍历每个位置找答案
        if(a[i]<M) vis[a[i]]=1;//如果这个数在查找范围内,标记已经出现过
        while(vis[primes[p]]) p++;//从前往后单调寻找第一个没有出现的质数
        ans[i]=primes[p];//答案
    }
    
    while(q--) {
        int x; cin>>x;
        cout<<ans[x]<<'\n';
    }
    
    return 0;
}

E.阿宁睡大觉

  • 题意

    • 给定一个只含有’Z’和’z’的字符串,可以进行删除操作,每次删除一个字符,最多删除k次

    • 求下式的最大值
      ∑ i = 1 l e n ( s ) − 1 w ( s i ) × w ( s i + 1 ) 其中 w ( Z ) = 2 , w ( z ) = 0 \sum_{i=1}^{len(s)-1}w(s_i)\times w(s_{i+1})\\ 其中w(Z)=2,w(z)=0 i=1len(s)1w(si)×w(si+1)其中w(Z)=2,w(z)=0

  • 题解

    • 由于只有’ZZ’的情况才能给答案做贡献,所以可以统计连续Z的子段来统计没有进行删除时的答案
    • 再统计所有z的连续子段及其长度(非开头和结尾,因为只要z在开头或者结尾删不删除对答案没有影响),从小到大排序去贪心删除这些子段,每删除一个子段答案多了一个ZZ的答案贡献
  • 代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
const int N=2e5+10;

int n,k,ans;
char s[N];
vector<int> sub;//存储z子段的长度

int main() {
    cin>>n>>k;
    cin>>s+1;
    for(int i=1;i<=n;i++) {
        int p=i;
        while(s[p]==s[i] && p<=n) p++;
        p--;
        if(s[i]=='Z') ans+=(p-i);//连续的Z子段对答案的贡献
        else if(i!=1 && p!=n) sub.push_back(p-i+1);//非两端的z子段记录
        i=p;
    }
    
    sort(sub.begin(),sub.end());//排序后,贪心删除zz子段
    for(auto x:sub) 
        if(x<=k) {k-=x; ans++;}
    cout<<ans*4<<'\n';//每个ZZ的分数为4
    
    return 0;
}

F.阿宁去游玩

  • 题意

    • 给定一个含n个节点的无向图,每个节点有0,1两种性质,如果性质相同那么边权为x,否则为y
    • 可以通过魔法将除了所在点的其他点都变换性质,花费边权z
    • 问从1到n的最短路为多少
  • 题解

    • 正权最短路可以直接用spfa
    • 建图,边权有两种情况,不用魔法直接是x(y),使用魔法为y+z(x+z),选其中边权小的即可。注意,相邻的点相对性质不变,所以不需要考虑全局怎么变化的
  • 代码

#include <iostream>
#include <queue>

using namespace std;
const int N=2e5+10;
typedef long long LL;
const LL INF=1e18+10;//注意数据范围

int n,m,x,y,z,a[N];//数组为每个节点的性质
int h[N],e[2*N],w[2*N],ne[2*N],idx;//无向图
bool st[N];//最短路
LL dis[N];

void add(int a,int b,int c) {//加一条权值为c的边
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

int main() {
    cin.tie(0)->sync_with_stdio(false);
    
    cin>>n>>m>>x>>y>>z;
    for(int i=1;i<=n;i++) cin>>a[i],h[i]=-1,dis[i]=INF;//初始化
    while(m--) {//建图
        int u,v;
        cin>>u>>v;
        if(a[u]==a[v]) {
            add(u,v,min(x,y+z));
            add(v,u,min(x,y+z));
        }
        else {
            add(u,v,min(y,x+z));
            add(v,u,min(y,x+z));
        }
    }
    
  //spfa最短路
    dis[1]=0;
    queue<int> q;
    q.push(1); st[1]=1;
    while(q.size()) {
        int t=q.front();q.pop(); st[t]=0;
        
        for(int i=h[t];~i;i=ne[i]) {
            int j=e[i];
            if(dis[j]>dis[t]+w[i]) {//注意是dis[t]和w[i]
                dis[j]=dis[t]+w[i];
                if(!st[j]) q.push(j),st[j]=1;
            }
        }
    }
    
    cout<<dis[n]<<'\n';//输出最短路答案
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值