Java题解,代码已去除冗余~~~

A 红魔塔

略,时间复杂度O(1)

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        System.out.println(Math.min(sc.nextInt()*sc.nextInt(),sc.nextInt()));
    }
}

B 冰冻青蛙

首先跟9个9不互质的数字不能小于n的三分之一,其次只需要把这样的数字贪心地各两个位置放置即可,时间复杂度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(),ans[]=new int[n];
        Set<Integer> set=new HashSet<>();
        Queue<Integer> q=new LinkedList<>();
        for(int i=1;i<=n;i++){
            if(gcd(999999999,i)!=1){
                q.add(i);
                set.add(i);
            }
        }
        if(set.size()*3<n){
            System.out.println("Baka!");
        }
        else{
            for(int i=1;i<=n;i++){
                if(set.add(i)){
                    q.add(i);
                }
            }
            for(int i=1;i<n;i+=3){
                ans[i]=q.poll();
            }
            for(int i=n-1;i>=0;i--){
                System.out.println((ans[i]==0?q.poll():ans[i])+" ");
            }
        }
    }
    static int gcd(int a,int b){
        return a<b?gcd(b,a):b==0?a:gcd(a%b,b);
    }
}

C 灵梦的字符串问题

记录每个字符后边最近的非本身字符的是什么,如果比自己大,则优先复制一次,否则不复制,时间复杂度O(nC),C==26

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],last[]=new int[30],next[]=new int[n+5];
        //last表示的是每一种字母最近出现的位置,next表示的的最近的不同字母在哪个位置
        long m=sc.nextLong();
        String s=sc.next();
        Arrays.fill(last,n+5);
        Arrays.fill(next,n+5);
        for(int i=0;i<n;i++){
            a[i]=sc.nextInt();
        }
        for(int i=n-1;i>=0;i--){
            int b=s.charAt(i)-'a';
            for(int j=0;j<26;j++){
                if(j!=b){
                    next[i]=Math.min(next[i],last[j]);
                }
            }
            last[b]=i;
        }
        StringBuilder ans=new StringBuilder();
        for(int i=0;i<n;i++){
            ans.append(s.charAt(i));
            if(m>=a[i]&&next[i]<n&&s.charAt(next[i])>s.charAt(i)){
                ans.append(s.charAt(i));
                m-=a[i];
            }
        }
        System.out.println(ans);
    }
}

D 幽幽子的魔法宴会

如果数组本身之和不小于y,很明显答案为0,否则钦定x的最高置位,选择所有这一位为0的数字选择,再谈心地往低位尝试填充,最后再次贪心从高到低尝试撤销置位,时间复杂度O(TnC^2),C==60

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        for(int i=sc.nextInt();i!=0;i--){
            int n=sc.nextInt(),a[]=new int[n];
            long y=sc.nextLong(),arrSum=0;
            for(int j=0;j<n;j++){
                a[j]=sc.nextInt();
                arrSum+=a[j];
            }
            if(arrSum>=y){
                System.out.println(0);
            }
            else{
                for(int j=0;j<=60;j++){
                    //钦定j为最高位,先验证是否有必要
                    long sum=0,ans=1L<<j,num=0,count[]=new long[j+5];
                    for(long b:a){
                        if((b>>j&1)==0){
                            //此时一定要选b,因为选择了会使得答案对出1<<j,比低置为的数加起来要大
                            num++;
                            //此时sum“临时”增加的值应为b的j位之前数位,以及j位
                            sum+=(b>>j<<j)+(1L<<j);
                            for(int k=0;k<j;k++){
                                count[k]+=b>>k&1;
                            }
                        }
                        else{
                            sum+=b;
                        }
                    }
                    //当这一位取1的时候贡献大于0(也就是0的置位大于一半数量)的时候,取1
                    for(int k=j-1;k>=0;k--){
                        if(count[k]*2<num){
                            ans|=1L<<k;
                            sum+=(num-count[k])*(1L<<k);
                        }
                        else{
                            sum+=count[k]*(1L<<k);
                        }
                    }
                    if(sum>=y){
                        for(int k=j-1;k>=0;k--){
                            if((ans>>k&1)==1){
                                if(sum+(1L<<k)*(count[k]*2-num)>=y){
                                    sum+=(1L<<k)*(count[k]*2-num);
                                    ans^=1L<<k;
                                }
                            }
                        }
                        System.out.println(ans);
                        break;
                    }
                }
            }
        }
    }
}

E 纯粹的退治

答案即为数组差分中的正数之和,每次操作即为对区间内数字加1或者减1,采用分块儿算法,记录每个块儿内可能对答案造成影响的0和1的数目,由于map全纪录会造成常数较大因此此处采用偏离量和数组记录部分数量,阈值采用50,时间复杂度O(能过)

import java.util.*;
public class Main{
    static int threshold=50;
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),q=sc.nextInt(),size=(int)Math.sqrt(n),inc[]=new int[n/size+5],pos[]=new int[n/size+5],nonNeg[]=new int[n/size+5];
        //inc表示的块儿内的数字偏移量,count表示的是块可能给答案造成贡献的数字的计数
        long a[]=new long[n],ans=0,count[][]=new long[n/size+5][threshold*2+5];
        for(int i=0;i<n;i++){
            a[i]=sc.nextLong();
        }
        for(int i=n-1;i>=0;i--){
            a[i]-=i==0?0:a[i-1];
            if(Math.abs(a[i])<=threshold){
                count[i/size][(int)a[i]+threshold]++;
            }
            if(a[i]>0){
                pos[i/size]++;
                ans+=a[i];
            }
            if(a[i]>=0){
                nonNeg[i/size]++;
            }
        }
        System.out.println(ans);
        for(int i=0;i<q;i++){
            int x=sc.nextInt(),p=sc.nextInt()-1;
            ans+=incOp(a,size,inc,pos,nonNeg,count,p+1,Math.min(p+x,n-1))-decOp(a,size,inc,pos,nonNeg,count,p-x+1,p);
            System.out.println(ans);
        }
    }
    static int incOp(long a[],int size,int inc[],int pos[],int nonNeg[],long count[][],int l,int r){
        if(l>r){
            return 0;
        }
        //区间+1操作
        //list1代表的是不完整的区间下标,list2代表完整区间
        List<Integer> list1=new ArrayList<>(),list2=new ArrayList<>();
        if(l/size==r/size){
            list1.add(l/size);
        }
        else{
            list1.add(l/size);
            list1.add(r/size);
            for(int i=l/size+1;i<r/size;i++){
                list2.add(i);
            }
        }
        int ans=0;
        //完整的块儿要直接处理,超过范围的数字要重新加入list1
        for(int b:list2){
            inc[b]++;
            if(inc[b]>threshold){
                inc[b]--;
                list1.add(b);
            }
            else{
                pos[b]+=count[b][threshold+1-inc[b]];
                ans+=pos[b];
                nonNeg[b]+=count[b][threshold-inc[b]];
            }
        }
        //不完整的块儿要重新洗牌
        for(int b:list1){
            Arrays.fill(count[b],0);
            nonNeg[b]=pos[b]=0;
            for(int i=size*b;i<size*(b+1)&&i<a.length;i++){
                a[i]+=inc[b]+(i>=l&&i<=r?1:0);
                if(Math.abs(a[i])<=threshold){
                    count[b][(int)a[i]+threshold]++;
                }
                if(a[i]>0){
                    pos[b]++;
                    //加1后为正数,说明对答案有贡献
                    if(i>=l&&i<=r){
                        ans++;
                    }
                }
                if(a[i]>=0){
                    nonNeg[b]++;
                }
            }
            inc[b]=0;
        }
        return ans;
    }
    static int decOp(long a[],int size,int inc[],int pos[],int nonNeg[],long count[][],int l,int r){
        if(l>r){
            return 0;
        }
        //区间-1操作
        //list1代表的是不完整的区间下标,list2代表完整区间
        List<Integer> list1=new ArrayList<>(),list2=new ArrayList<>();
        if(l/size==r/size){
            list1.add(l/size);
        }
        else{
            list1.add(l/size);
            list1.add(r/size);
            for(int i=l/size+1;i<r/size;i++){
                list2.add(i);
            }
        }
        int ans=0;
        //完整的块儿要直接处理,超过范围的数字要重新加入list1
        for(int b:list2){
            inc[b]--;
            if(inc[b]<-threshold){
                inc[b]++;
                list1.add(b);
            }
            else{
                pos[b]-=count[b][threshold-inc[b]];
                nonNeg[b]-=count[b][threshold-1-inc[b]];
                ans+=nonNeg[b];
            }
        }
        //不完整的块儿要重新洗牌
        for(int b:list1){
            //map[b].clear();
            Arrays.fill(count[b],0);
            nonNeg[b]=pos[b]=0;
            for(int i=size*b;i<size*(b+1)&&i<a.length;i++){
                a[i]+=inc[b]-(i>=l&&i<=r?1:0);//此处应为减
                if(Math.abs(a[i])<=threshold){
                    count[b][threshold+(int)a[i]]++;
                }
                if(a[i]>=0){
                    nonNeg[b]++;
                    //减1后为非负数,说明对答案有贡献
                    if(i>=l&&i<=r){
                        ans++;
                    }
                }
                if(a[i]>0){
                    pos[b]++;
                }
            }
            inc[b]=0;
        }
        return ans;
    }
}

这里给出应map计数的超时代码:TLE

F 斯卡雷特家的游戏

博弈,待完善,时间复杂度O(Tn)

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        for(int i=sc.nextInt();i!=0;i--){
            int n=sc.nextInt();
            boolean hasOne=false;
            for(int j=0;j<n;j++){
                hasOne|=sc.nextInt()==1;
            }
            System.out.println(n==1||!hasOne?"Remilia":"Flandre");
        }
    }
}