C~G Java题解

C 相助 && E 相依

最佳的方式就是分段的连续的段,直到删完,因为要是两段存在包含,那么删除外边的一大段次数减1,更优,因此记录每个下标结尾的删完需要的最少次数,另外还要记录一下之前同数字之前所有删完的最少次数以备查阅,时间复杂度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],last[]=new int[500005],ans[]=new int[n+1];
        Arrays.fill(last,n+10);
        for(int i=0;i<n;i++){
            a[i]=sc.nextInt();
            ans[i+1]=1+last[a[i]];
            last[a[i]]=Math.min(last[a[i]],ans[i]);
        }
        System.out.println(ans[n]<=n?ans[n]:-1);
    }
}

D 异或炸弹(easy) && F 异或炸弹(hard)

简单版的可以逐行差分,,复杂版本参考链接,叫什么切比雪夫转化的坐标变换,也不知道为啥,,,哎,时间复杂度O(p^2),其中p==3000

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(),count[][]=new int[6100][6100],ans=0;
        for(int i=0;i<m;i++){
            int x=sc.nextInt(),y=sc.nextInt(),r=sc.nextInt(),px=x+y,py=x-y+3002;
            count[Math.max(px-r,1)][Math.max(py-r,1)]^=1;
            count[Math.max(px-r,1)][Math.min(py+r+1,6010)]^=1;
            count[Math.min(px+r+1,6010)][Math.max(py-r,1)]^=1;
            count[Math.min(px+r+1,6010)][Math.min(py+r+1,6010)]^=1;
        }
        for(int i=1;i<=6002;i++){
            for(int j=1;j<=6002;j++){
                count[i][j]^=count[i-1][j-1]^count[i][j-1]^count[i-1][j];
                if(check(n,i,j)){
                    ans+=count[i][j];
                }
            }
        }
        System.out.println(ans);
    }
    static boolean check(int n,int a,int b){
        if((a-b)%2==0){
            int x=(a+b-3002)/2,y=(a-b+3002)/2;
            return x>=1&&x<=n&&y>=1&&y<=n;
        }
        return false;
    }
}

G 回文串

线段树记录正向哈希以及反向哈希,修改和求哈希是需要修改懒标记的,时间复杂度O(n+q*(logn)^2)

import java.io.*;
public class Main{
    static long base=137,mod=(int)1e9+7,pre[]=new long[200005];
    public static void main(String args[]) throws IOException{
        BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
        String arr[]=bf.readLine().split(" ");
        int n=Integer.parseInt(arr[0]),q=Integer.parseInt(arr[1]);
        pre[0]=1;
        for(int i=1;i<=n;i++){
            pre[i]=(pre[i-1]*base+1)%mod;
        }
        String s=bf.readLine();
        SegTree st=new SegTree(0,n-1);
        build(st,s);
        for(int i=0;i<q;i++){
            arr=bf.readLine().split(" ");
            if(arr[0].equals("1")){
                int l=Integer.parseInt(arr[1])-1,r=Integer.parseInt(arr[2])-1;
                bw.write(check(st,l,r)?"YES\n":"NO\n");
            }
            else{
                int l=Integer.parseInt(arr[1])-1,r=Integer.parseInt(arr[2])-1;
                char c=arr[3].charAt(0);
                modify(st,l,r,c);
            }
        }
        bw.flush();
    }
    static boolean check(SegTree st,int a,int b){
        if(find(st,a,b,1)==find(st,a,b,2)){
            return true;
        }
        int s1=a+(b-a-1)/2,s2=b-(b-a-1)/2,l=-1,r=(b-a-1)/2;
        while(l<r){
            int mid=l+(r-l)/2;
            if(find(st,s1-mid,s1,1)==find(st,s2,s2+mid,2)){
                l=mid;
            }
            else{
                r=mid-1;
            }
            if(l==r-1){
                if(find(st,s1-r,s1,1)==find(st,s2,s2+r,2)){
                    l=r;
                }
                break;
            }
        }
        return find(st,a,s1-l-2,1)==find(st,s2+l+2,b,2);
    }
    static void modify(SegTree st,int a,int b,int c){
        int l=st.l,r=st.r;;
        if(a==l&&b==r){
            st.cur=c;
            st.hash1=st.hash2=pre[r-l]*c%mod;
        }
        else{
            clear(st);
            int mid=(l+r)>>1;
            if(b<=mid){
                modify(st.left,a,b,c);
            }
            else if(a>mid){
                modify(st.right,a,b,c);
            }
            else{
                modify(st.left,a,mid,c);
                modify(st.right,mid+1,b,c);
            }
            update(st);
        }
    }
    static long find(SegTree st,int a,int b,int c){
        if(a>b){
            return 0;
        }
        int l=st.l,r=st.r;
        if(l==a&&r==b){
            return c==1?st.hash1:st.hash2;
        }
        clear(st);
        int mid=(l+r)>>1;
        if(b<=mid){
            return find(st.left,a,b,c);
        }
        else if(a>mid){
            return find(st.right,a,b,c);
        }
        long part1=find(st.left,a,mid,c),part2=find(st.right,mid+1,b,c);
        return c==1?(part1+part2*pow(mid+1-a))%mod:(part2+part1*pow(b-mid))%mod;
    }
    static void build(SegTree st,String s){
        int l=st.l,r=st.r;
        if(l==r){
            st.hash1=st.hash2=s.charAt(l);
        }
        else{
            int mid=(l+r)>>1;
            st.left=new SegTree(l,mid);
            st.right=new SegTree(mid+1,r);
            build(st.left,s);
            build(st.right,s);
            update(st);
        }
    }
    static void update(SegTree st){
        //子节点更新父节点
        int l=st.l,r=st.r,mid=(l+r)>>1;
        st.hash1=(st.left.hash1+st.right.hash1*pow(mid+1-l))%mod;
        st.hash2=(st.right.hash2+st.left.hash2*pow(r-mid))%mod;
    }
    static void clear(SegTree st){
        //父节点更新子节点
        int l=st.l,r=st.r;
        if(st.cur==-1||l==r){
            return;
        }
        int mid=(l+r)>>1;
        st.left.hash1=st.left.hash2=(st.cur*pre[mid-l])%mod;
        st.right.hash2=st.right.hash1=(st.cur*pre[r-mid-1])%mod;
        st.left.cur=st.cur;
        st.right.cur=st.cur;
        st.cur=-1;
    }
    static long pow(int a){
        return (pre[a]+mod-pre[a-1])%mod;
    }
}
class SegTree{
    SegTree left,right;
    int l,r,cur;
    //hash1表示的左边低次哈希,hash2右边低次
    long hash1,hash2;
    public SegTree(int l,int r){
        this.l=l;
        this.r=r;
        cur=-1;
    }
}