原博客链接:https://blog.nowcoder.net/n/16c41ade73cd41d6bcf1b058de58786b

A

模拟

import java.util.*;
import java.io.*;

public class Main {
	static Scanner sc = new Scanner(System.in);
	public static void main(String[]args) throws IOException{
        int a = sc.next().length(),b = sc.next().length();
        if(a==6||b==6) {
            System.out.println(-1);
		}
		else {
			System.out.println(Math.abs(a-b)+1);
		}
	}
}

B

分类讨论。特判0,1各一个的情况。

import java.util.*;
import java.io.*;

public class Main {
	static Scanner sc = new Scanner(System.in);
	public static void main(String[]args) throws IOException{
        int n=sc.nextInt();
		char []s = ("*"+sc.next()).toCharArray();
		int []cnt = new int [2];
		for(int i=1;i<=n;i++) {
			cnt[s[i]-'0']++;
		}
		if(cnt[0]==n||cnt[1]==n) {
			System.out.println(0);return;
		}
		if(cnt[0]==cnt[1]&&cnt[1]==1) {
			System.out.println(-1);return;
		}
		if(cnt[0]==cnt[1]) System.out.println(2);
		else System.out.println(1);
	}
}

C

枚举 右端点 , 显然不会左移,故可二分or双指针。

import java.util.*;
import java.io.*;

public class Main {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in),65535);
	static StreamTokenizer st = new StreamTokenizer(bf);
	public static void main(String[]args) throws IOException{
		int n=I();long ans=0;
		long []a = new long[n+2];
		for(int i=1;i<=n;i++) {
			int x=I();
			a[i] = a[i-1]+x;
		}
           int p=2;
		for(int i=1;i+2<=n;i++) {
			int l=i+1;
            while(p<n && (a[i]>=a[p]-a[i] || a[p]-a[i]<= a[n]-a[p]))
			    p++;
            ans += n-p;
		}
		System.out.println(ans);
	}
	
	static int I() throws IOException{
		st.nextToken();
		return (int)st.nval;
	}
}

D

巨大多分类讨论。当心负数。

import java.util.*;
import java.io.*;

public class Main {
	static Scanner sc = new Scanner(System.in);
	public static void main(String[]args) throws IOException{
        int t=sc.nextInt();
        long ans=0;
        while(t-->0){
            int n=sc.nextInt();
			long a=sc.nextInt(),b=sc.nextInt();
			int []cnt = new int [6];
			cnt[0]=cnt[1]=0;
			ans=0;
			for(int i=1;i<=n;i++) {
				int x= sc.nextInt();
				cnt[x%2]++;
			}
			if(a<0&&b<0) {
				for(int i=0;i<2;i++) {
					ans += a*(cnt[i]-1)*cnt[i]/2;
				}
				ans += b*cnt[0]*cnt[1];
			}
			else if(a<0&&b>=0) {
				for(int i=0;i<2;i++) {
					ans += a*(cnt[i]-1)*cnt[i]/2;
				}
				if(cnt[0]>0&&cnt[1]>0) ans += b;
			}
			else if(a>=0&&b<0) {
				ans = b*cnt[0]*cnt[1];
				if(ans==0) {
					ans = (n-1)*a;
				}
			}else {
				if(cnt[0]==0||cnt[1]==0) ans=(n-1)*a;
				else {
					if(a<b) {
						if(n>=2) ans=b+(n-2)*a;
					}
					else {
						ans=(n-1)*b;
					}
				}
			}
			System.out.println(ans);
        }
	}
}

E

离散化+树状数组。

一下看哪些结点满足条件 但不满足条件 ,这样删除该结点子孙的子树可能会使其成为支撑结点,设该类结点为半支撑结点。

第二次 ,对于当前结点,看是否有祖先半支撑结点,满足删除当前结点子树可以转化成支撑结点,将这些结点统计进答案,并删除当前节点子树的支撑点数量。

需满足: ,即 ,其中 表示该节点下层结点权值和, 为结点权值,可用树状数组查询。由于数据范围达到 ,需离散化。

import java.util.*;
import java.io.*;

public class Main {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in),65535);
	static StreamTokenizer st = new StreamTokenizer(bf);
	static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
	static int n,m,maxn=200005,inf = 0x3f3f3f3f;
	static long ans=0,mod=(int)1e9+7,INF=(long)2e18;
	public static void main(String[]args) throws IOException{
		new Task().main();
		pw.flush();
	}
	
	static int I() throws IOException{
		st.nextToken();
		return (int)st.nval;
	}

	static class Task{
		void main()throws IOException{
			int t=1;
			//t=sc.nextI();
			while(t-->0) solve();
		}
		
		int []a = new int [maxn];
		Vector<Vector<Integer>>g = new Vector<>();
		int []cnt = new int[maxn];//自下向上的稳定点数量(包含自身)
		long []s2 = new long [maxn];//当前结点下层结点权值之和
		boolean []tf = new boolean[maxn];//条件1
		boolean []df = new boolean[maxn];//条件2
		Map<Long,Integer> mp = new HashMap<>();
		Vector<Long> vv = new Vector<>();
		BIT tr = new BIT();
		long ans2=0;
		
		private void solve() throws IOException {
			n=I();
			for(int i=1;i<=n;i++) a[i]=I();
			for(int i=0;i<=n;i++) g.add(new Vector<>());
			for(int i=1;i<=n;i++) {
				int x=I();
				g.get(x).add(i);
			}
			dfs(1,0);
			for(int i=1;i<=n;i++) 
                if(tf[i]&&!df[i]) vv.add((long)(s2[i]-a[i]));
			Collections.sort(vv);
			m=0;
			for(long x:vv) {
				if(!mp.containsKey(x)) {
					mp.put(x, ++m);//离散化
				}
			}
			tr.maxn=m;
			dfs2(1);
			pw.println(Math.max(ans, ans2));
		}

		private void dfs2(int i) {
			if(tf[i]&&!df[i]) {
				tr.modify(mp.get(s2[i]-a[i]), 1);
			}
			for(int x:g.get(i)) {
				long sum = s2[x]+a[x];//子树权值和
				int r = find(sum);//找到小于等于该节点权值的值的离散化索引
				if(r!=-1) {
					ans2 = Math.max(ans2, ans-cnt[x]+tr.qu(r));
				}
				dfs2(x);
			}
			if(tf[i]&&!df[i]) {
				tr.modify(mp.get(s2[i]-a[i]), -1);
			}
		}
		
		private int find(long sum) {
			int l=1,r=vv.size();
			int p=-1;
			while(l<=r) {
				int mid=(l+r)/2;
				if(vv.get(mid-1)<=sum) {
					p=mid-1;
					l=mid+1;
				}
				else r=mid-1;
			}
			return p>=0?mp.get(vv.get(p)):-1;
		}

		private long dfs(int i, long sum) {
			if(sum>=a[i]) tf[i]=true;
			long res=0;
			for(int x:g.get(i)) {
				res+=dfs(x,sum+a[i]);
				cnt[i] += cnt[x];
			}
			if(res<=a[i]) df[i]=true;
			df[i]=df[i]&&tf[i];
			s2[i] = res;
			if(df[i]) {
				ans++;
				cnt[i]++;
			}
			return res+a[i];
		}
	}
}

class BIT {
	int maxn=200005;
	int []t = new int [maxn];
	
	int lowbit(int x) {
		return x&-x;
	}
	
	int qu(int x) {
		int ans = 0;
		for(int i=x;i>0;i-=lowbit(i)) {
			ans += t[i];
		}
		return ans;
	}
	
	void modify(int x,int v) {
		for(int i=x;i<=maxn;i+=lowbit(i)) {
			t[i] += v;
		}
	}
	
}

F

思维。

表示当前所有值在 内的数的数量。遍历每个前缀 ,将当前数 更新至 ,然后求新的逆序对数量,为之前所有比它大的数的数量,可 转移。

之后循环将数组开头的数移到末尾,动态更新逆序对数量。先减去比它小的数的数量,再加上比它大的数的数量。

复杂度: ( 为卡 设置较大,确实比较吓人

import java.util.*;
import java.io.*;

public class Main {
	static Scanner sc = new Scanner(System.in);
	public static void main(String[]args) throws IOException{
		int n=sc.nextInt();
        int []a = new int [n+5];
		int sum[] = new int [n+5];
        long ans=0;
		for(int i=1;i<=n;i++) a[i]=sc.nextInt();
		for(int i=1;i<=n;i++) {
			ans += sum[n]-sum[a[i]];
			long res=ans,w=ans;
			for(int j=a[i];j<=n;j++) sum[j]++;
			for(int j=1;j<i;j++) {
				res = res - sum[a[j]-1] + i-sum[a[j]];
				w = Math.min(res, w);
			}
			System.out.print(w+" ");
		}
	}
}