C~F Java

C 苗苗的气球

方法一:猜结论

假如能够销完的话,总数一定是偶数,并且最大的数量的二倍不大于总数,那么就假设每种颜色是剩下的颜色,判断剩下的(剩下的假如是奇数的话需要从当前遍历的气球种类借一个进来),能留下的条件妖魔石剩下的可以自我消耗完,要么剩下的最大数量被抵消完后的数量小于当前遍历,实现上利用了有序映射计数,时间复杂度O(nlogn)

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],ans=0;
        TreeMap<Integer,Integer> map=new TreeMap<>();
        inc(map,0,1);
        long sum=0;
        for(int i=0;i<n;i++){
            a[i]=sc.nextInt();
            inc(map,a[i],1);
            sum+=a[i];
        }
        for(int b:a){
            sum-=b;
            inc(map,b,-1);
            int max=map.lastKey();
            if(sum%2==0&&b>max*2-sum||sum%2==1&&b>1&&(max*2<=sum+1||b>max*2-sum)){
                ans++;
            }
            inc(map,b,1);
            sum+=b;
        }
        System.out.println(ans);
    }
    static void inc(TreeMap<Integer,Integer> map,int a,int b){
        map.put(a,map.getOrDefault(a,0)+b);
        if(map.get(a)==0){
            map.remove(a);
        }
    }
}

方法二:简便做法

待定

D 萌萌的好数

方法一:数位动态规划

很给的一个题,不解释,时间复杂度O(C+Tnlogn),其中C==480,为预处理的固定时间

import java.util.*;
public class Main{
    public static void main(String args[]){
        long count[][][]=new long[17][10][3];
        for(int i=0;i<10;i++){
            if(i!=3){
                count[1][i][i%3]=1;
            }
        }
        for(int i=2;i<17;i++){
            for(int j=0;j<10;j++){
                for(int k=0;k<3;k++){
                    for(int p=0;p<10;p++){
                        count[i][j][k]+=count[i-1][p][(k+30-j)%3];
                    }
                }
            }
        }
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++){
            long n=sc.nextLong();
            long l=0,r=n*10;
            while(l<r){
                long mid=(l+r)>>1;
                if(find(mid,count)>=n){
                    r=mid;
                }
                else{
                    l=mid+1;
                }
                if(l==r-1){
                    if(find(l,count)>=n){
                        r=l;
                    }
                    break;
                }
            }
            System.out.println(r);
        }
    }
    static long find(long a,long count[][][]){
        List<Long> list=new ArrayList<>();
        while(a!=0){
            list.add(a%10);
            a/=10;
        }
        int size=list.size();
        long ans=0,pre=0;
        for(int i=size-1;i>=0;i--){
            a=list.get(i);
            for(int j=0;j<a;j++){
                for(int k=1;k<3;k++){
                    ans+=count[i+1][j][(int)(k+30-pre)%3];
                }
            }
            pre=(pre+a)%3;
            if(i==0&&pre!=0&&a!=3){
                ans++;
            }
        }
        return ans;
    }
}

方法二:打表

每30个数中有18个,打表即可,时间复杂度O(1)

import java.util.*;
public class Main{
    static int move[]={1,2,4,5,7,8,10,11,14,16,17,19,20,22,25,26,28,29};
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++){
            long n=sc.nextLong();
            System.out.println((n-1)/18*30+move[(int)((n-1)%18)]);
        }
    }
}

E 茜茜的计算器

横对称+纵对称-横纵对称,时间复杂度O(log(mod))

import java.util.*;
public class Main{
    static int mod=(int)1e9+7;
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        System.out.println(n%2==0?(pow(4,n/2)+pow(4,n)-pow(2,n/2)+mod)%mod:(pow(4,n/2)*2+pow(4,n)-pow(2,n/2)*2+mod*2L)%mod);
    }
    static long pow(long a,int b){
        long ans=1;
        while(b!=0){
            if(b%2==1){
                ans=ans*a%mod;
            }
            b>>=1;
            a=a*a%mod;
        }
        return ans;
    }
}

F 花花的地图

方法一:一格更新整列

最短路的思路,每次遇到障碍物的格子,假如得到的新距离可以更新该格子的最短距离,则直接更新整列的距离,优先队列实现,时间复杂度O(nm^2log(mn))

import java.util.*;
public class Main{
    static int move[][]={{0,1},{0,-1},{1,0},{-1,0}};
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),m=sc.nextInt(),c[]=new int[m],dis[][]=new int[n][m];
        String s[]=new String[n];
        for(int i=0;i<n;i++){
            s[i]=sc.next();
            Arrays.fill(dis[i],(int)1e9);
        }
        dis[0][0]=0;
        for(int i=0;i<m;i++){
            c[i]=sc.nextInt();
        }
        Queue<int[]> q=new PriorityQueue<>((a,b)->Integer.compare(a[2],b[2]));
        q.add(new int[]{0,0,0});
        while(!q.isEmpty()){
            int a[]=q.poll();
            if(dis[a[0]][a[1]]<a[2]){
                continue;
            }
            for(int mo[]:move){
                int x=a[0]+mo[0],y=a[1]+mo[1];
                if(x>=0&&x<n&&y>=0&&y<m){
                    int d=a[2]+(s[x].charAt(y)=='#'?c[y]:0);
                    if(d<dis[x][y]){
                        dis[x][y]=d;
                        q.add(new int[]{x,y,d});
                        if(s[x].charAt(y)=='#'){
                            for(int k=0;k<n;k++){
                                if(dis[k][y]>d){
                                    dis[k][y]=d;
                                    q.add(new int[]{k,y,d});
                                }
                            }
                        }
                    }
                }
            }
        }
        System.out.println(dis[n-1][m-1]);
    }
}

方法二:建图

根据视频讲解,每一列建立一个虚拟点,代表一次性摧毁一列的所有障碍,建图后进行最短路,实现上用了优先队列,时间复杂度O(mnlog(mn))

import java.util.*;
public class Main{
    static int move[][]={{0,1},{0,-1},{1,0},{-1,0}};
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),m=sc.nextInt(),c[]=new int[m],dis[][]=new int[n+1][m];
        String s[]=new String[n];
        List<int[]> path[][]=new List[n+1][m];
        for(int i=0;i<=n;i++){
            Arrays.fill(dis[i],(int)1e9);
            for(int j=0;j<m;j++){
                path[i][j]=new ArrayList<>();
            }
            if(i<n){
                s[i]=sc.next();
            }
        }
        for(int i=0;i<m;i++){
            c[i]=sc.nextInt();
        }
        dis[0][0]=0;
        Queue<int[]> q=new PriorityQueue<>((a,b)->Integer.compare(a[2],b[2]));
        q.add(new int[]{0,0,0});
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(s[i].charAt(j)=='#'){
                    path[n][j].add(new int[]{i,j,0});
                }
                for(int mo[]:move){
                    int x=i+mo[0],y=j+mo[1];
                    if(x>=0&&x<n&&y>=0&&y<m){
                        if(s[x].charAt(y)=='#'){
                            path[i][j].add(new int[]{n,y,c[y]});
                        }
                        else{
                            path[i][j].add(new int[]{x,y,0});
                        }
                    }
                }
            }
        }
        while(!q.isEmpty()){
            int a[]=q.poll();
            if(dis[a[0]][a[1]]<a[2]){
                continue;
            }
            for(int b[]:path[a[0]][a[1]]){
                int d=a[2]+b[2];
                if(d<dis[b[0]][b[1]]){
                    dis[b[0]][b[1]]=d;
                    q.add(new int[]{b[0],b[1],d});
                }
            }
        }
        System.out.println(dis[n-1][m-1]);
    }
}

方法三:动态规划