二分贪心合集

题目描述

小蓝发现了一个有趣的数列,这个数列的前几项如下:

1,1,2,1,2,3,1,2,3,4,⋯1,1,2,1,2,3,1,2,3,4,⋯

小蓝发现,这个数列前 11 项是整数 11,接下来 22 项是整数 11 至 22,接下来 33 项是整数 11 至 33,接下来 44 项是整数 11 至 4,依次类推。

小蓝想知道,这个数列中,连续一段的和是多少。

输入描述

输入的第一行包含一个整数 TT,表示询问的个数。

接下来 TT 行,每行包含一组询问,其中第 ii 行包含两个整数 lili​ 和 riri​,表示询问数列中第 lili​ 个数到第 riri​ 个数的和。

输出描述

输出 TT 行,每行包含一个整数表示对应询问的答案。

输入输出样例

示例

输入

3
1 1
1 3
5 8

输出

1
4
8

评测用例规模与约定

对于 1010% 的评测用例,1≤T≤30,1≤li≤ri≤1001≤T≤30,1≤li​≤ri​≤100。

对于 2020% 的评测用例,1≤T≤100,1≤li≤ri≤10001≤T≤100,1≤li​≤ri​≤1000。

对于 4040% 的评测用例,1≤T≤1000,1≤li≤ri≤1061≤T≤1000,1≤li​≤ri​≤106。

对于 7070% 的评测用例,1≤T≤10000,1≤li≤ri≤1091≤T≤10000,1≤li​≤ri​≤109。

对于 8080% 的评测用例,1≤T≤1000,1≤li≤ri≤10121≤T≤1000,1≤li​≤ri​≤1012。

对于 9090% 的评测用例,1≤T≤10000,1≤li≤ri≤10121≤T≤10000,1≤li​≤ri​≤1012。

对于所有评测用例,1≤T≤100000,1≤li≤ri≤10121≤T≤100000,1≤li​≤ri​≤1012。

运行限制

  • 最大运行时间:5s
  • 最大运行内存: 256M

暴力会超时

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
     public static void main(String[] args) {
     Scanner scan = new Scanner(System.in);
     //在此输入您的代码...
     int n=scan.nextInt();
     int[] a=new int[n+1];
     int[] b=new int[n+1];
     int[] c=new int[n+1];
     for(int i=1;i<=n;i++) {
         a[i]=scan.nextInt();
     }
         for(int j=1;j<=n;j++) {
             b[j]=scan.nextInt();
         }
             for(int k=1;k<=n;k++) {
                 c[k]=scan.nextInt();
             }
     int sum=0;
     scan.close();
     for(int i=1;i<=n;i++) {
         for(int j=1;j<=n;j++) {
             for(int k=1;k<=n;k++) {
                 if(a[i]<b[j]&&b[j]<c[k]) {
                     sum++;
                 }
             }
         }
     }
     System.out.println(sum);
 }
}

 仍然会超时

import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
      Scanner scan = new Scanner(System.in);
     //在此输入您的代码...
     int n=scan.nextInt();
     int[] a=new int[n+1];
     int[] b=new int[n+1];
     int[] c=new int[n+1];
     for(int i=1;i<=n;i++) {
    	 a[i]=scan.nextInt();
     }
     for(int j=1;j<=n;j++) {
    	b[j]=scan.nextInt();
     }
     for(int k=1;k<=n;k++) {
    	c[k]=scan.nextInt();
     }
     scan.close();
     int s=0;
     int[] ab=new int[n+1];
     int[] bc=new int[n+1];
     Arrays.sort(a);
     Arrays.sort(b);
     Arrays.sort(c);
     for(int i=1;i<n+1;i++) {
    	 for(int j=1;j<n+1;j++) {
    		 if(b[i]>a[j]) {
    			 ab[i]++;
    		 }
    	 }
     }
     for(int i=1;i<n+1;i++) {
      //  int s=0;
    	 for(int j=1;j<n+1;j++) {
    		 if(b[i]<c[j]) {
    			 bc[i]++;
    		 }
    	 }
     }
     int sum=0;
     for(int i=1;i<n+1;i++) {
    	 sum+=ab[i]*bc[i];
     }
     System.out.println(sum);
 }
}

指针:

import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
     Scanner scan = new Scanner(System.in);
     //在此输入您的代码...
     int n=scan.nextInt();
     int[] a=new int[n];
     int[] b=new int[n];
     int[] c=new int[n];
     for(int i=0;i<n;i++) {
    	 a[i]=scan.nextInt();
     }
     for(int j=0;j<n;j++) {
    	b[j]=scan.nextInt();
     }
     for(int k=0;k<n;k++) {
    	c[k]=scan.nextInt();
     }
     scan.close();
     Arrays.sort(a);
     Arrays.sort(b);
     Arrays.sort(c);
     long sum=0;
     int p=0,q=0;
     for(int i=0;i<n;i++) {
    	 while(p<n&&a[p]<b[i]) {
    		 p++;
    	 }
    	 while(q<n&&c[q]<=b[i]) {
    		 q++;
    	 }
        sum+=((long)p*(n-q));
     }
     System.out.println(sum);
 }
}

分巧克力:

题目描述

儿童节那天有 K 位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。

小明一共有 NN 块巧克力,其中第 ii 块是 Hi×WiHi​×Wi 的方格组成的长方形。为了公平起见,

小明需要从这 NN 块巧克力中切出 K 块巧克力分给小朋友们。切出的巧克力需要满足:

  1. 形状是正方形,边长是整数;

  2. 大小相同;

例如一块 6x5 的巧克力可以切出 6 块 2x2 的巧克力或者 2 块 3x3 的巧克力。

当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?

输入描述

第一行包含两个整数 N,KN,K (1≤N,K≤1051≤N,K≤105)。

以下 N 行每行包含两个整数 Hi,WiHi​,Wi​ (1≤Hi,Wi≤1051≤Hi​,Wi​≤105)。

输入保证每位小朋友至少能获得一块 1x1 的巧克力。

输出描述

输出切出的正方形巧克力最大可能的边长。

输入输出样例

示例

输入

2 10
6 5
5 6

输出

2

运行限制

  • 最大运行时间:2s
  • 最大运行内存: 256M
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int k=scan.nextInt();
		int[] len=new int[n];
		int[] wid=new int[n];
		for(int i=0;i<n;i++) {
			len[i]=scan.nextInt();
			wid[i]=scan.nextInt();
		}
		scan.close();
		int l=1,r=100001,ans=0;
		while(l<=r) {
			int sum=0;
			int mid=(l+r)/2;
			for(int i=0;i<n;i++) {
				sum+=(len[i]/mid)*(wid[i]/mid);
			}
			if(sum>=k) {
				l=mid+1;
				ans=mid;
			}else {
				r=mid-1;
			}
		}
		System.out.println(ans);
	}
}

小明的衣服:

题目描述

小明买了 nn 件白色的衣服,他觉得所有衣服都是一种颜色太单调,希望对这些衣服进行染色,每次染色时,他会将某种颜色的所有衣服寄去染色厂,第 ii 件衣服的邮费为 aiai​ 元,染色厂会按照小明的要求将其中一部分衣服染成同一种任意的颜色,之后将衣服寄给小明, 请问小明要将 nn 件衣服染成不同颜色的最小代价是多少?

输入描述

第一行为一个整数 nn ,表示衣服的数量。

第二行包括 nn 个整数 a1,a2...ana1​,a2​...an​ 表示第 ii 件衣服的邮费为 aiai​ 元。

(1≤n≤105,1≤ai≤1091≤n≤105,1≤ai​≤109 )

输出描述

输出一个整数表示小明所要花费的最小代价。

输入输出样例

示例 1

输入

5
5 1 3 2 1 

输出

25

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

http://t.csdn.cn/ewC4u

哈夫曼树的构造

注意:用PriorityQueue中的isEmpty()可能会超时,可以使用q.size()判断队列不为空

import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
   public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		long sum=0,h;
		PriorityQueue<Long> q=new PriorityQueue<Long>();
		for(int i=0;i<n;i++) {
			h=scan.nextLong();
			q.add(h);
		}
		scan.close();
		while(q.size()>1) {
			long a=q.peek();
			q.poll();
			if(q.peek()!=null) {
				long b=q.peek();
				q.poll();
				long c=a+b;
				sum+=c;
				q.add(c);
			}	
		}
		System.out.println(sum);
	}
}

答疑:

题目描述

有 n位同学同时找老师答疑。每位同学都预先估计了自己答疑的时间。

老师可以安排答疑的顺序,同学们要依次进入老师办公室答疑。 一位同学答疑的过程如下:

  1. 首先进入办公室,编号为 i的同学需要 si毫秒的时间。
  2. 然后同学问问题老师解答,编号为 i的同学需要 aiai​ 毫秒的时间。
  3. 答疑完成后,同学很高兴,会在课程群里面发一条消息,需要的时间可 以忽略。
  4. 最后同学收拾东西离开办公室,需要 ei毫秒的时间。一般需要 1000 秒、2000 秒或 3030 秒,即 ei 取值为 10000,20000 或 30000。

一位同学离开办公室后,紧接着下一位同学就可以进入办公室了。

答疑从 0 时刻开始。老师想合理的安排答疑的顺序,使得同学们在课程群 里面发消息的时刻之和最小。

输入描述

输入第一行包含一个整数 n,表示同学的数量。

接下来 nn 行,描述每位同学的时间。其中第 i行包含三个整数 si, ai​, ei,意义如上所述。

其中有 ,1≤n≤1000,1≤si≤60000,1≤ai≤106,ei∈10000,20000,300001≤n≤1000,1≤si​≤60000,1≤ai​≤106,ei​∈10000,20000,30000,即 ei一定是 10000、20000、30000 之一。

输出描述

输出一个整数,表示同学们在课程群里面发消息的时刻之和最小是多少。

输入输出样例

示例

输入

3
10000 10000 10000
20000 50000 20000
30000 20000 30000

输出

280000

运行限制

  • 最大运行时间:3s
  • 最大运行内存: 128M

文章问的是发消息时刻的和,当而不是发消息的时间,注意审题

 

import java.util.*;
//class C{
//	long a;
//	long b;
//	public C(long a,long b) {
//		this.a=a;
//		this.b=b;
//	}
//}
public class 答疑 {
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int[][] a=new int[n][2];
		for(int i=0;i<n;i++) {
			int s=scan.nextInt();
			int b=scan.nextInt();
			a[i][1]=scan.nextInt();
			a[i][0]=s+b;
		}
		Arrays.sort(a,(b,c) -> b[0]+b[1]-c[0]-c[1]);
		long sum=0;
		for(int i=0;i<n;i++) {
			sum+=(long)a[i][0]*(n-i)+a[i][1]*(n-i-1);
		}
		System.out.println(sum);
	}
}

美丽的区间:

题目描述

给定一个长度为 nn 的序列 a1,a2,⋯ ,ana1​,a2​,⋯,an​ 和一个常数 SS。

对于一个连续区间如果它的区间和大于或等于 SS,则称它为美丽的区间。

对于一个美丽的区间,如果其区间长度越短,它就越美丽。

请你从序列中找出最美丽的区间​。

输入描述

第一行包含两个整数 n,Sn,S,其含义如题所述。

接下来一行包含 nn 个整数,分别表示 a1,a2,⋯ ,ana1​,a2​,⋯,an​。

10≤N≤10510≤N≤105,1×ai≤1041×ai​≤104,1≤S≤1081≤S≤108。

输出描述

输出共一行,包含一个整数,表示最美丽的区间的长度。

若不存在任何美丽的区间,则输出 00。

输入输出样例

示例 1

输入

5 6
1 2 3 4 5

输出

2

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

尺取法:http://t.csdn.cn/q7Yqs

import java.util.*;
public class 最美的区间 {
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int[] a=new int[n];
		int s=scan.nextInt();
		for(int i=0;i<n;i++) {
			a[i]=scan.nextInt();
		}
		int l=0,r=0,sum=0,len=n+1;
		for(;r<n;r++) {
			sum+=a[r];
			while(l<=r&&sum>=s) {
				if(len>r-l+1) {
					len=r-l+1;
				}
				sum-=a[l];
				l++;
			}
		}
		if(len==n+1) {
			len=0;
		}
		System.out.println(len);
	}
}

杨辉三角形:

题目描述

下面的图形是著名的杨辉三角形:

如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列: 1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯

给定一个正整数 NN,请你输出数列中第一次出现 NN 是在第几个数?

输入描述

输入一个整数 NN。

输出描述

输出一个整数代表答案。

输入输出样例

示例 1

输入

6

输出

13

评测用例规模与约定

对于 2020​​ 的评测用例,1≤N≤101≤N≤10​; 对于所有评测用例,1≤N≤10000000001≤N≤1000000000。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

 该列起始的数    行数=列数*2

import java.util.*;
public class 杨辉三角形 {
	public static int n;
	public static long f(long a,long b) {	//通过数学排列公式计算出该处杨辉三角形的值
		long res=1;
		for(long i=a,j=1;j<=b;i--,j++) {
			res=res*i/j;
			if(res>n) {
				return res;
			}
		}
		return res;
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		n=scan.nextInt();
		scan.close();
		for(int k=16;k>=0;k--) {	//从第16列开始循环,每次循环列数减1
			int l=2*k;				//二分的左边界和右边界
			int r=n;
			while(l<=r) {
				int mid=(l+r)/2;
				long rr=f(mid,k);	//通过函数获取得到mid行k列的杨辉三角形的值为多少
				if(rr>n) {	
					r=mid-1;
				}else if(rr<n){
					l=mid+1;
				}else {				//rr等于n,将二维坐标转化为一维输出
					System.out.println((long)(mid+1)*mid/2+k+1);
					return;
				}
			}
		}
	}
}

谈判:

题目描述

在很久很久以前,有 nn 个部落居住在平原上,依次编号为 11 到 nn。第 ii 个部落的人数为 titi​。

有一年发生了灾荒。年轻的政治家小蓝想要说服所有部落一同应对灾荒,他能通过谈判来说服部落进行联合。

每次谈判,小蓝只能邀请两个部落参加,花费的金币数量为两个部落的人数之和,谈判的效果是两个部落联合成一个部落(人数为原来两个部落的人数之和)。

输入描述

输入的第一行包含一个整数 nn,表示部落的数量。

第二行包含 nn 个正整数,依次表示每个部落的人数。

其中,1≤n≤1000,1≤ti≤1041≤n≤1000,1≤ti​≤104。

输出描述

输出一个整数,表示最小花费。

输入输出样例

示例 1

输入

4
9 1 3 5

输出

31

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		PriorityQueue<Long> q=new PriorityQueue<Long>(); 
		for(int i=0;i<n;i++) {
			long b=scan.nextLong();
			q.add(b);
		}
		scan.close();
		long sum=0,k=0;
		while(q.size()>0) {
			long c=q.peek();
			q.poll();
			if(q.peek()!=null) {
				long d=q.peek();
				q.poll();
				k=c+d;
				sum+=k;
				q.add(k);
			}
			
		}
		System.out.println(sum);
	}
}

一元三次方程求解:

题目描述

有形如:ax3+bx2+cx+d=0ax3+bx2+cx+d=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,da,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在 −100−100 至 100100 之间),且根与根之差的绝对值 ≥1≥1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后 22 位。

提示:记方程 f(x)=0f(x)=0,若存在 22 个数 x1x1​ 和 x2x2​,且x1<x2x1​<x2​,f(x1)×f(x2)<0f(x1​)×f(x2​)<0,则在 (x1,x2)(x1​,x2​)之间一定有一个根。

输入描述

输入一行,44 个实数 a,b,c,da,b,c,d。

输出描述

输出一行,33 个实根,从小到大输出,并精确到小数点后 22 位。

输入输出样例

示例 1

输入

1 -5 -4 20

输出

-2.00 2.00 5.00

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M
import java.util.*;
public class 一元三次方程求解 {
	static double a;
	static double b;
	static double c;
	static double d;
	public static double f(double x) {			//带入x求方程的值
		double v=Math.pow(x, 3)*a+Math.pow(x,2)*b+x*c+d;
		return v;
	}
	public static double find(double l,double r) {		//找到区间内的解
		double mid=(l+r)/2;
		while(r-l>0.001) {
			if(f(mid)==0) {
				return mid;
			}else if(f(mid)*f(l)<0) {
				r=mid;
			}else {
				l=mid;
			}
			mid=(l+r)/2;
		}
		return mid;
	}
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		a=scan.nextDouble();
		b=scan.nextDouble();
		c=scan.nextDouble();
		d=scan.nextDouble();
		scan.close();
		int flag=0;
		for(double s=-100;s<=100&&flag!=3;s++) {
			if(f(s)==0) {
				flag++;
				System.out.printf(String.format("%.2f",s)+" ");
			}
			if(f(s)*f(s+1)<0) {
				System.out.printf(String.format("%.2f", find(s,s+1))+" ");
			}
		}

	}
}

删除字符:

题目描述

给定一个单词,请问在单词中删除 tt 个字母后,能得到的字典序最小的单词是什么?

输入描述

输入的第一行包含一个单词,由大写英文字母组成。

第二行包含一个正整数 tt。

其中,单词长度不超过 100100,tt 小于单词长度。

输出描述

输出一个单词,表示答案。

输入输出样例

示例 1

输入

LANQIAO
3

输出

AIAO

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

首先要知道什么是字典序,顾名思义,查字典的序列,要保证序最小,如果前面比后面大,则删除前面的,如果后面的大则删除后面的

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		String str=scan.nextLine();
		int n=scan.nextInt();
		scan.close();
		StringBuffer s=new StringBuffer(str);
		while(n>0) {
			if(s.charAt(0)>=s.charAt(1)) {
				s.deleteCharAt(0);
				n--;
			}else {
				s.deleteCharAt(1);
				n--;
			}
		}
		System.out.println(s);
	}
}

付账问题:

题目描述

几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。

现在有 nn 个人出去吃饭,他们总共消费了 SS 元。其中第 ii 个人带了 aiai​元。幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢?

为了公平起见,我们希望在总付钱量恰好为 SS 的前提下,最后每个人付的钱的标准差最小。这里我们约定,每个人支付的钱数可以是任意非负实数,即可以不是 1 分钱的整数倍。你需要输出最小的标准差是多少。

标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的"偏差有多大"。形式化地说,设第 ii 个人付的钱为 bibi​ 元,那么标准差为 :

S=1n∑i=1n(bi−1n∑i=1nbi)2S=n1​∑i=1n​(bi​−n1​∑i=1n​bi​)2

输入描述

第一行包含两个整数 n、Sn、S;

第二行包含 nn 个非负整数 a1, ⋯ , ana1​, ⋯, an​。

其中,n≤5×105,0≤ai≤109n≤5×105,0≤ai​≤109 。

输出描述

输出最小的标准差,四舍五入保留 4 位小数。

保证正确答案在加上或减去 10−910−9 后不会导致四舍五入的结果发生变化。

输入输出样例

示例

输入

5 2333
666 666 666 666 666

输出

0.0000

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

只通过了百分之八十,剩下的超时,实在没想到好的想法

import java.util.Scanner;
import java.util.Arrays;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
    	public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        int n=scan.nextInt();
        long s=scan.nextLong();
        long[] a=new long[n];
        for(int i=0;i<n;i++) {
            a[i]=scan.nextInt();
        }
        scan.close();
        Arrays.sort(a);
        double ans = 0,avg;
        avg=1.0*s/n;		//总的平均值
        for(int i=0;i<n;i++) {
        	double avgg=1.0*s/(n-i);	//算出当前的平均值,即为每个人应该付的钱数
            if(a[i]<avgg) {        //第i个钱的多少*当前人数<当前的总额,即第i个钱小于当前的平均值
                ans+=(a[i]-avg)*(a[i]-avg);        //小于当前平均值,则这个钱全部付掉,累加到方差
                s-=a[i];                //第i个钱全部付出,还需要再付的总钱数,递推后i+1到n个数,直到不用将钱都付掉
            }else {                    //当前的钱数超过平均值
                ans+=(avg-avgg)*(avg-avgg)*(n-i);                //(平均付的钱数-平均应该钱数)的平方 后n-i个人累加到方差
                break;
            }
        }
        System.out.printf("%.4f\n",Math.sqrt(ans/n));
    }
}

最大子矩阵:

问题描述

小明有一个大小为 N×MN×M 的矩阵, 可以理解为一个 NN 行 MM 列的二维数组。

我们定义一个矩阵 mm 的稳定度 f(m)f(m) 为 f(m)=max⁡(m)−min⁡(m)f(m)=max(m)−min(m), 其中 max⁡(m)max(m) 表示矩阵 mm 中的最大值, min⁡(m)min(m) 表示矩阵 mm 中的最小值。

现在小明想要从这个矩阵中找到一个稳定度不大于 limit 的子矩阵, 同时他还希望这个子矩阵的面积越大越好 (面积可以理解为矩阵中元素个数)。

子矩阵定义如下: 从原矩阵中选择一组连续的行和一组连续的列, 这些行列交点上的元素组成的矩阵即为一个子矩阵。

输入格式

第一行输入两个整数 N,MN,M, 表示矩阵的大小。

接下来 NN 行, 侮行输入 MM 个整数,表示这个矩阵。

最后一行输入一个整数 limit, 表示限制。

辎出格式

输出一个整数. 分别表示小明选择的子矩阵的最大面积。

样例输入

3 4
2 0 7 9
0 6 9 7
8 4 6 4
8

样例输出

6

样例说明

满足稳定度不大于 8 的且面积最大的子矩阵总共有三个, 他们的面积都是 6 (粗体表示子矩阵元素)

2 0 7 9

0 6 9 7

8 4 6 4

2 0 7 9

0 6 9 7

8 4 6 4

2 0 7 9

0 6 9 7

8 4 6 4

评测用例规模与约定

对于所有评测用例, 0≤0≤ 矩阵元素值, limit ≤105≤105 。

运行限制

  • 最大运行时间:5s
  • 最大运行内存: 512M

翻硬币:

题目描述

小明正在玩一个"翻硬币"的游戏。

桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。

比如,可能情形是:**oo***oooo;

如果同时翻转左边的两个硬币,则变为:oooo***oooo。

现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?

我们约定:把翻动相邻的两个硬币叫做一步操作。

输入描述

两行等长的字符串,分别表示初始状态和要达到的目标状态。

每行的长度<1000。

输出描述

一个整数,表示最小操作步数。

输入输出样例

示例

输入

**********
o****o****

输出

5

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 64M

import java.util.*;
public class  翻硬币  {
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		String str1=scan.nextLine();
		String str2=scan.nextLine();
		scan.close();
		char[] a=new char[str2.length()];
		a=str1.toCharArray();
		char[] b=new char[str2.length()];
		b=str2.toCharArray();
		int sum=0;
		for(int i=0;i<str1.length()-1;i++) {
			if(a[i]!=b[i]) {
				a[i]=b[i];
				if(a[i+1]=='o') {
					a[i+1]='*';
				}else {
					a[i+1]='o';
				}
				sum++;
			}
		}
		System.out.println(sum);
		}
	}

卡牌:

问题描述

这天, 小明在整理他的卡牌。

他一共有 nn 种卡牌, 第 ii 种卡牌上印有正整数数 i(i∈[1,n])i(i∈[1,n]), 且第 ii 种卡牌 现有 aiai​ 张。

而如果有 nn 张卡牌, 其中每种卡牌各一张, 那么这 nn 张卡牌可以被称为一 套牌。小明为了凑出尽可能多套牌, 拿出了 mm 张空白牌, 他可以在上面写上数 ii, 将其当做第 ii 种牌来凑出套牌。然而小明觉得手写的牌不太美观, 决定第 ii 种牌最多手写 bibi​ 张。

请问小明最多能凑出多少套牌?

输入格式

输入共 3 行, 第一行为两个正整数 n,mn,m 。

第二行为 nn 个正整数 a1,a2,…,ana1​,a2​,…,an​ 。

第三行为 nn 个正整数 b1,b2,…,bnb1​,b2​,…,bn​ 。

输出格式

一行, 一个整数表示答案。

样例输入

4 5
1 2 3 4
5 5 5 5

样例输出

3

样例说明

这 5 张空白牌中, 拿 2 张写 1 , 拿 1 张写 2 , 这样每种牌的牌数就变为了 3,3,3,43,3,3,4, 可以凑出 3 套牌, 剩下 2 张空白牌不能再帮助小明凑出一套。

评测用例规模与约定

对于 30%30% 的数据, 保证 n≤2000n≤2000;

对于 100%100% 的数据, 保证 n≤2×105;ai,bi≤2n;m≤n2n≤2×105;ai​,bi​≤2n;m≤n2 。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 512M

http://t.csdn.cn/5OsEz

import java.util.Scanner;
import java.util.Arrays;
import java.util.Comparator;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		long m=scan.nextLong();
		int[][] a=new int[n][2];
		for(int i=0;i<n;i++) {
			a[i][0]=scan.nextInt();
		}
		for(int i=0;i<n;i++) {
			a[i][1]=scan.nextInt();
		}
		scan.close();
		Arrays.sort(a,Comparator.comparingInt(b->b[0]));
		long k=m;
		while(a[0][1]>0&&m>0) {
			int d=a[0][0];
			int c=a[0][1];
			a[0][0]++;
			a[0][1]--;
			m--;
			Arrays.sort(a,Comparator.comparingInt(b->b[0]));
			//if(d==a[0][0]&&c==a[0][1]) {
			//    break;
			//}
		}
		System.out.println(a[0][0]);
	}
}

但是上述方法中,时间复杂度为N^N^logN,已经远远超过十的八次方了

没AC,,,看看佬们的代码

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

public class Main {
  static final int N = (int) 2e5 + 10;
  static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  static final PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

  static int[] a = new int[N], b = new int[N];
  static int n;
  static long m;

  static boolean check(int mid) {
    long tm = m;
    //模拟分配
    for (int i = 1; i <= n; i++) {
      if (mid > a[i] && b[i] >= mid - a[i]) {
        tm -= mid - a[i];
      } else if (mid > a[i] && b[i] < mid - a[i]) return false;
      //牌不够使用了
      if (tm < 0) return false;
    }
    return true;
  }

  public static void main(String[] args) throws IOException {
    String[] ss = br.readLine().trim().split(" ");
    n = Integer.parseInt(ss[0]);
    m = Long.parseLong(ss[1]);
    ss = br.readLine().trim().split(" ");
    for (int i = 1; i <= n; i++) a[i] = Integer.parseInt(ss[i - 1]);
    ss = br.readLine().trim().split(" ");
    for (int i = 1; i <= n; i++) b[i] = Integer.parseInt(ss[i - 1]);
    int minh = a[1] + b[1];
    for (int i = 2; i <= n; i++) minh = Math.min(minh, a[i] + b[i]);

    //二分牌的套数
    int l = 0, r = minh;
    while (l < r) {
      int mid = (l + r + 1) >> 1;
      if (check(mid)) l = mid;
      else r = mid - 1;
    }
    out.println(l);
    out.close();
  }
}

统计字符串:

题目描述

如果一个字符串 SS 恰好可以由某个字符串重复 KK 次得到,我们就称 SS 是 KK 次重复字符串。例如 abcabcabc 可以看作是 abc 重复 33 次得到,所以 abcabcabc 是 33 次重复字符串。

同理 aaaaaa 既是 22 次重复字符串、又是 33 次重复字符串和 66 次重复字符串。

现在给定一个字符串 SS,请你计算最少要修改其中几个字符,可以使 SS 变为一个 KK 次字符串?

输入描述

输入第一行包含一个整数 KK。

第二行包含一个只含小写字母的字符串 SS。

其中,1≤K≤105,1≤∣S∣≤1051≤K≤105,1≤∣S∣≤105。其中 ∣S∣∣S∣ 表示 SS 的 长度。

输出描述

输出一个整数代表答案。如果 SS 无法修改成 KK 次重复字符串,输出 −1−1。

输入输出样例

示例 1

输入

2
aabbaa

输出

2

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

统计子矩阵:

问题描述

给定一个 N×MN×M 的矩阵 AA, 请你统计有多少个子矩阵 (最小 1×11×1, 最大 N×M)N×M) 满足子矩阵中所有数的和不超过给定的整数 KK ?

输入格式

第一行包含三个整数 N,MN,M 和 KK.

之后 NN 行每行包含 MM 个整数, 代表矩阵 AA.

输出格式

一个整数代表答案。

样例输入

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12

样例输出

19

样例说明

满足条件的子矩阵一共有 19 , 包含:

大小为 1×11×1 的有 10 个。

大小为 1×21×2 的有 3 个。

大小为 1×31×3 的有 2 个。

大小为 1×41×4 的有 1 个。

大小为 2×12×1 的有 3 个。

评测用例规模与约定

对于 30%30% 的数据, N,M≤20N,M≤20.

对于 70%70% 的数据, N,M≤100N,M≤100.

对于 100%100% 的数据, 1≤N,M≤500;0≤Aij≤1000;1≤K≤2500000001≤N,M≤500;0≤Aij​≤1000;1≤K≤250000000.

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

 

import java.util.*;
public class 统计子矩阵 {
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int m=scan.nextInt();
		int k=scan.nextInt();
		int[][] a=new int[n+1][m+1];
		int[][] s=new int[n+1][m+1];
		for(int i=1;i<n+1;i++) {
			for(int j=1;j<m+1;j++) {
				a[i][j]=scan.nextInt();
				s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+a[i][j];			//求二维数组前缀和
			}
		}
		scan.close();
		long sum=0;
		for(int li=1;li<=n;li++) {
			for(int ri=li;ri<=n;ri++) {
				for(int lj=1;lj<=m;lj++) {
					for(int rj=lj;rj<=m;rj++) {
						if(li>=1&&lj>=1) {
							if(s[ri][rj]-s[ri][lj-1]-s[li-1][rj]+s[li-1][lj-1]<=k) {
								sum++;
							}	
						}
					}
				}
			}
		}
		System.out.println(sum);
	}
}

时间复杂度为N^4

 

 

import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int m=scan.nextInt();
		int k=scan.nextInt();
		int[][] a=new int[n+1][m+1];
		for(int i=1;i<n+1;i++) {			//预处理每一列的前缀和
			for(int j=1;j<m+1;j++) {
				a[i][j]=scan.nextInt();
				a[i][j]+=a[i-1][j];			
			}
		}
		scan.close();
		long ans=0;
		for(int i=1;i<n+1;i++) {						//控制的是从第几行开始
			for(int j=i;j<n+1;j++) {					//控制的是到第几行
				//从第i行到j行,每一列看做一个数字a[j][1:m]-a[i-1][1:m]
				for(int l=1,r=1,sum=0;r<=m;r++) {		//控制的是列,以双指针作为控制条件
					sum+=a[j][r]-a[i-1][r];
					while(sum>k) {
						sum-=a[j][l]-a[i-1][l];
						l++;
					}
					ans+=r-l+1;
				}
			}
		}
		System.out.println(ans);
	}
}

但是Java的输入是有劣势的,和上一题一样,输入过于占用时间,仍有三个未通过,来看一下大佬的代码:

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

public class Main {
    
    static int N = 510;
    static long a[][] = new long[N][N];
    static int n, m;
    static long k;
    
    public static boolean check(int x1, int y1, int x2, int y2){
        long t = a[x2][y2] - a[x2][y1-1] - a[x1-1][y2] + a[x1-1][y1-1];
        return t <= k;
    }

    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StreamTokenizer stmInput = new StreamTokenizer(br);
        stmInput.nextToken();
        n = (int)stmInput.nval;
        stmInput.nextToken();
        m = (int)stmInput.nval;
        stmInput.nextToken();
        k = (long)stmInput.nval;
        
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                stmInput.nextToken();
                a[i][j] = (long)stmInput.nval;
                a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1]; 
            }
        }
        long ans = 0;
        for(int x1 = 1; x1 <= n; x1++) {
            for(int x2 = x1; x2 <= n; x2++) {
                // 固定行后,枚举列
                for(int y2 = 1, y1 = 1; y2 <= m; y2++){
                    while(y1 <= y2 && !check(x1, y1, x2, y2)){
                        y1++; // 使得在列y1和y2之间的子矩阵都满足要求
                    }
                    ans += y2 - y1 + 1; // 累加子矩阵的个数
                }
            }
        }
        bw.write(ans + "\n");
        bw.flush();
        bw.close();
        br.close();
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值