BDEF Java

B 小红的伪回文子串(easy) && E 小红的伪回文子串(hard)

遍历每个字符,字符需要跟前边遍历过的字符的配对儿计算贡献(必须跟当前不同),贡献量要么是当前位置距离串尾的距离,要么是前边某个字符距离串首的距离,两者距离取较小值,实现的时候可以按照26个字母记录两个前缀和:一个是字母距离串首的距离之和,一个是遍历到该位置字母数量总和;贡献求得时候分成两部分求即可,时间复杂度O(nC),其中是n是字符串长度,C==26

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        String s=sc.next();
        int n=s.length(),count[][]=new int[n+1][26];
        long ans=0,pre[][]=new long[n+1][26];
        for(int i=1;i<n;i++){
            count[i]=count[i-1].clone();
            pre[i]=pre[i-1].clone();
            count[i][s.charAt(i-1)-'a']++;
            pre[i][s.charAt(i-1)-'a']+=i;
            int idx=Math.min(n-2-i,i-1);
            for(int j=0;j<26;j++){
                if(j!=s.charAt(i)-'a'){
                    ans+=pre[idx+1][j]+(n-i)*(count[i][j]-count[idx+1][j]);
                }
            }
        }
        System.out.println(ans);
    }
}

D 小红的乘2除2

三种情况,在一个数字上操作,在相邻数字上操作,再不相邻数字上操作,计算变化值的最小值,其中第三种情况统计的时候用前后缀来降低复杂度,时间复杂度O(n)

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+5];
        long sum=0,min=(long)1e18;
        for(int i=1;i<=n;i++){
            a[i]=sc.nextInt();
            if(i>1){
                sum+=Math.abs(a[i]-a[i-1]);
            }
        }
        int b[]=a.clone();
        //修改单个位置:
        for(int i=1;i<=n;i++){
            min=Math.min(min,find(n,a,b,new int[][]{{i,0},{i,1}}));
        }
        //修改相邻位置:
        for(int i=2;i<=n;i++){
            min=Math.min(min,find(n,a,b,new int[][]{{i,0},{i-1,1}}));
            min=Math.min(min,find(n,a,b,new int[][]{{i-1,0},{i,1}}));
        }
        //修改不相邻位置:
        long left1[]=new long[n+5],left2[]=new long[n+5],right1[]=new long[n+5],right2[]=new long[n+5];
        left1[0]=left2[0]=right1[n+1]=right2[n+1]=(long)1e18;
        for(int i=1;i<=n;i++){
            left1[i]=Math.min(left1[i-1],find(n,a,b,new int[][]{{i,0}}));
            left2[i]=Math.min(left2[i-1],find(n,a,b,new int[][]{{i,1}}));
        }
        for(int i=n;i>=1;i--){
            right1[i]=Math.min(right1[i+1],find(n,a,b,new int[][]{{i,0}}));
            right2[i]=Math.min(right2[i+1],find(n,a,b,new int[][]{{i,1}}));
        }
        for(int i=2;i<n;i++){
            min=Math.min(min,left1[i-1]+right2[i+1]);
            min=Math.min(min,left2[i-1]+right1[i+1]);
        }
        System.out.println(sum+min);
    }
    static long find(int n,int a[],int b[],int idx[][]){
        int maxIdx=-1,minIdx=n+1;
        long d1=0,d2=0;
        for(int c[]:idx){
            maxIdx=Math.max(maxIdx,c[0]);
            minIdx=Math.min(minIdx,c[0]);
        }
        for(int i=minIdx;i<=maxIdx+1;i++){
            if(i<=n&&i>1){
                d1+=Math.abs((long)b[i]-b[i-1]);
            }
        }
        for(int c[]:idx){
            if(c[1]==0){
                b[c[0]]>>=1;
            }
            else{
                b[c[0]]<<=1;
            }
        }
        for(int i=minIdx;i<=maxIdx+1;i++){
            if(i<a.length&&i>1){
                d2+=Math.abs((long)b[i]-b[i-1]);
            }
        }
        for(int c[]:idx){
            b[c[0]]=a[c[0]];
        }
        return d2-d1;
    }
}

F 小红的迷宫行走

预处理1-1e5数字的约数,建图,把每个数字看做一个点,再把每个点跟自己的约数正反连边,跑最短路, 时间复杂度O(ClogC+能过)

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