题解 | 牛客小白月赛92 BCDEFG

获得木头

https://ac.nowcoder.com/acm/contest/81126/A

B 采矿时间到!

思路:第二四排的宝石需要1个体力来得到,而第一五排的宝石需要多少体力得到,取决于它靠近矿道的那一个位置是否有宝石,贪心地先取得所有1体力的宝石,再去取2体力的,事时间复杂度O(n+h)

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),h=sc.nextInt(),ans=0,count[]=new int[3];
        String s[]=new String[5];
        for(int i=0;i<5;i++){
            s[i]=sc.next();
        }
        for(int i=0;i<n;i++){
            if(s[1].charAt(i)=='*'){
                count[1]++;
                if(s[0].charAt(i)=='*'){
                    count[1]++;
                }
            }
            else if(s[0].charAt(i)=='*'){
                count[2]++;
            }
            if(s[3].charAt(i)=='*'){
                count[1]++;
                if(s[4].charAt(i)=='*'){
                    count[1]++;
                }
            }
            else if(s[4].charAt(i)=='*'){
                count[2]++;
            }
        }
        for(int i=1;i<=2;i++){
            if(h>=count[i]*i){
                ans+=count[i];
                h-=count[i]*i;
            }
            else{
                ans+=h/i;
                break;
            }
        }
        System.out.println(ans);
    }
}

C 耕种时间到!

经过估计,每个种子最多可以播种20轮,因此,循环到不能播种(或者说直到等级小于等于x)为止,记录每一轮播种得到的x等级种子数量的总和,时间复杂度O(nlogC),其中C==1e9

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),a[]=new int[n];
        long count[]=new long[55],ans=0;
        for(int i=0;i<n;i++){
            a[i]=sc.nextInt();
        }
        int x=sc.nextInt();
        for(int b:a){
            find(b,x,count);
        }
        for(long b:count){
            ans=Math.max(ans,b);
        }
        System.out.println(ans);
    }
    static void find(int a,int x,long count[]){
        long num=1;
        for(int i=1;;i++,num<<=1,a=(a+2)/3){
            if(a==x){
                count[i]+=num;
                break;
            }
            if(a<x){
                break;
            }
        }
    }
}

D 探索的时光

整理成一个关于位置x的一元二次函数,计算系数后,从0到n-1逐一尝试,时间复杂度O(n)

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        //f(x)=a*x^2+b*x+c
        long a=0,b=0,c=0,ans=(long)9e18;
        int n=sc.nextInt();
        for(int i=0;i<n;i++){
            int ai=sc.nextInt();
            a+=ai;
            b-=ai*2*i;
            c+=(long)ai*i*i;
        }
        for(int i=0;i<n;i++){
            ans=Math.min(ans,a*i*i+b*i+c);
        }
        System.out.println(ans);
    }
}

E 来硬的

分组背包问题,难点在于只能用一次魔法,因此分别记录使用了魔法的最短时间以及未使用魔法的最短时间,注意更新顺序,时间复杂度O(nm)

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),m=sc.nextInt();
        long count0[]=new long[m+1],count1[]=new long[m+1];
        Arrays.fill(count0,(long)1e18);
        Arrays.fill(count1,(long)1e18);
        count0[0]=0;
        for(int i=0;i<n;i++){
            int x=sc.nextInt(),y=sc.nextInt();
            for(int j=m;j>=0;j--){
                //使用了魔法:
                count1[j]=Math.min(count1[j],count1[Math.max(0,j-x)]+y);
                count1[j]=Math.min(count1[j],count0[Math.max(0,j-x*2)]+y/2);
                //没使用魔法:
                count0[j]=Math.min(count0[j],count0[Math.max(0,j-x)]+y);
            }
        }
        System.out.println(Math.min(count0[m],count1[m]));
    }
}

F 快快乐乐剪羊毛

对于每只羊,其贡献发生变化只有可能在边界上的时候,因此利用差分思想记录每个边界的增量即可得到总的贡献之和,时间复杂度O(mnlog(mn))

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),m=sc.nextInt(),v[]=new int[n];
        long w[]=new long[n+1],pre=0;
        for(int i=1;i<=n;i++){
            w[i]=w[i-1]+sc.nextInt();
        }
        for(int i=0;i<n;i++){
            v[i]=sc.nextInt();
        }
        TreeMap<Long,Long> map=new TreeMap<>();
        for(int i=0;i<m;i++){
            int x=sc.nextInt();
            for(int j=1;j<=n;j++){
                modify(map,w[j-1]-x,v[j-1]);
                modify(map,w[j]-x,-v[j-1]);
            }
        }
        Set<Long> set=new HashSet<>();
        set.add(0L);
        for(long a:map.values()){
            pre+=a;
            set.add(pre);
        }
        System.out.println(set.size());
    }
    static void modify(TreeMap<Long,Long> map,long a,long b){
        map.put(a,map.getOrDefault(a,0L)+b);
    }
}

G 不速之客

方法一:折半预处理,固定时间复杂度为O(sqrt(C)*(logC)^2),其中C==1e10

import java.util.*;
public class Main{
    static int mod=998244353;
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        long n=sc.nextLong(),k=sc.nextLong(),ans=0;
        List<Long> list[]=new List[12];
        for(int i=0;i<12;i++){
            //m==i的时候,最大的后缀位数可以是i/2
            list[i]=new ArrayList<>();
            for(int j=(int)Math.pow(10,i>>1)-1;j>=0;j--){
                list[i].add(cal(j,i,j));
            }
            Collections.sort(list[i]);
        }
        int digitCount=findNumDigits(n);
        //先处理位数小于这个数的数字
        for(int i=1;i<digitCount;i++){
            int num2=i/2,num1=i-i/2;//前后半部分的位数
            int low=(int)Math.pow(10,num1-1),high=low*10;
            for(int j=low;j<high;j++){
                long cur=cal(j,i,j*(long)Math.pow(10,num2));
                ans+=find(list[i],k-cur)-find(list[i],-k-1-cur);
            }
        }
        //处理位数相同,且前缀小于的数字
        int num2=digitCount/2,num1=digitCount-digitCount/2;//前后半部分的位数
        int low=(int)Math.pow(10,num1-1),high=(int)(n/(int)Math.pow(10,num2));
        for(int i=high-1;i>=low;i--){
            long cur=cal(i,digitCount,i*(long)Math.pow(10,num2));
            ans+=find(list[digitCount],k-cur)-find(list[digitCount],-k-1-cur);
        }
        //处理位数相同,且前缀相同的数字,一个个尝试
        long cur=cal(high,digitCount,high*(long)Math.pow(10,num2)),suf=n%(int)Math.pow(10,num2);
        for(int i=0;i<=suf;i++){
            if(Math.abs(cur+cal(i,digitCount,i))<=k){
                ans++;
            }
        }
        System.out.println(ans%mod*pow(n%mod,mod-2)%mod);
    }
    static int find(List<Long> list,long max){
        if(list.get(0)>max){
            return 0;
        }
        int l=0,r=list.size()-1;
        while(l<r){
            int mid=(l+r)>>1;
            if(list.get(mid)<=max){
                l=mid;
            }
            else{
                r=mid-1;
            }
            if(l==r-1){
                if(list.get(r)<=max){
                    l=r;
                }
                break;
            }
        }
        return l+1;
    }
    static int findNumDigits(long a){
        //计算一个数在10进制下的位数
        int ans=0;
        while(a!=0){
            ans++;
            a/=10;
        }
        return ans;
    }
    static long cal(long a,int b,long c){
        //计算数字a在m==b的时候的f(a)
        long ans=-c;
        for(;a!=0;a/=10){
            ans+=(long)Math.pow(a%10,b);
        }
        return ans;
    }
    static long pow(long a,int b){
        //快速幂
        long ans=1;
        for(;b!=0;b>>=1,a=a*a%mod){
            if(b%2==1){
                ans=ans*a%mod;
            }
        }
        return ans;
    }
}

方法二:听说还有其他奇怪的算法,挖个坑吧先。。。。

全部评论

相关推荐

Yushuu:你的确很厉害,但是有一个小问题:谁问你了?我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了😆
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务