目录
1.ASC
【问题描述】
已知大写字母 A 的 ASCII 码为 65,请问大写字母 L 的 ASCII 码是多少?
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
也可直接计算
A | B | C | D | E | F | G | H | I | J | K | L |
65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 |
import java.util.Scanner;
public class Main{
public static void main(String[] args)throws Exception{
Scanner in = new Scanner(System.in);
String b = in.next();
for( int i=0;i< b.length();i++){
System.out.println( b.charAt(i)+" "+(byte) b.charAt(i));
}
}
}
答案:76
2.卡片
【问题描述】
小蓝有很多数字卡片,每张卡片上都是数字 0 到 9。
小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。
小蓝想知道自己能从 1 拼到多少。
例如,当小蓝有 30 张卡片,其中 0 到 9 各 3 张,则小蓝可以拼出 1 到 10,但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。
现在小蓝手里有 0 到 9 的卡片各 2021 张,共 20210 张,请问小蓝可以从 1拼到多少?
提示:建议使用计算机编程解决问题。【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
这题求从1开始的连续的数。
toCharArray()该方法的作用是返回一个字符数组,该字符数组中存放了当前字符串中的所有字符。
估计可能拼出3000多个数,编程打印出1~3500,复制到word文档上
public class Main {
public static void main(String[] args) {
for(int i=1;i<=3500;i++)
System.out.println(i);
}
}
public class Main {
public static void main(String[] args) {
int kp[] = new int[10];
//赋值
for(int i = 0 ; i <= 9 ; i ++){
kp[i] = 2021;//每种卡片2021张
}
System.out.println(def(kp));
}
//判断是否是从1到x的连续的数
public static int def(int kp[]){
int i;
for(i = 1 ; i < 20210 ; i ++){
int t = i;//防止死循环
//对每个数去余,余数就是要--的那个下标
while(t > 0 ){
kp[t%10]--;
//只要断片就给他结束
if(kp[t%10] <= 0 ){
return i;
}
t /= 10;
}
}
return 0;
}
}
public class Main {
public static void main(String[] args) {
int num = 0;
//从1开始拼接卡片,明显得出卡片1消耗的最快
for(int i=1;i<20210;i++) {
String s=i+"";
//char(int)根据ascii码取得其对应的字符
//toCharArray()该方法的作用是返回一个字符数组,该字符数组中存放了当前字符串中的所有字符
char a[]=s.toCharArray();
for(int j=0;j<a.length;j++) {
if(a[j]=='1') {
num++;
}
}
if(num>=2021) {
System.out.println(i);
break;
}
}
}
}
public class Main {
public static void main(String[] args) {
new Main().run();
}
void run() {
System.out.println(calc(2021));
}
int calc(int upper) {
int[] count = new int[10];
for(int n=1,k=1; ;k = ++n) {
do
if(++count[k%10]>upper)
return n-1;
while((k/=10)>0);
}
}
}
import java.util.Arrays;
public class Main{
public static void main(String[] args) {
int[] hash = new int[10];
Arrays.fill(hash, 2021);
long num = 0;
boolean flag;
do {
num++;
flag = true;
char[] str = String.valueOf(num).toCharArray();
for (char bit : str) {
if (hash[bit - '0'] > 0) {
hash[bit - '0']--;
} else {
flag = false;
break;
}
}
} while (flag);
System.out.println(num - 1);
}
}
public class Main {
public static void main(String[] args) {
int[] num = new int[10];//我们用长度为10的数组,来模拟数值为0~9的卡片
int temp;
int t;
int i;
boolean flag = false;
//每一张都有2021张
for(i = 0; i < 10; i++) {
num[i] = 2021;//数值为2的卡片有2021张
}
for(i = 1;; i++) {
temp = i; //用一层从1开始的for循环,来模拟小蓝想知道的:自己能从1拼到多少,由于 i 的值不能随意改变,所以将其值交给 temp 来管理
//想要拼得的数字是12,那么我们就需要一张1,一张2,用过之后我们就不能再用了。
//整数的拆分。12拆分成1和2,即12 --> 12 % 10 = 2 --> 12 / 10 = 1
//while循环内部的if语句,它的意思是判断此时想拼的数字是否能拼出来。就比如题目中所提到的11拼不出来的问题
while(temp != 0) {
t = temp % 10;
if(num[t] <= 0) {
flag = true;
break;
}
num[t]--;
temp /= 10;
}
if(flag) {
break;
}
}
System.out.println(i-1);
}
}
答案:3181
3.直线
【问题描述】
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。
给定平面上2×3个整点(x,y)0≤x<2.0≤y<3,x∈Zy∈Z),即横坐标是0到1(包含0和1)之间的整数、纵坐标是0到2(包含0和2)之间的整数的点。这些点一共确定了11条不同的直线。
给定平面上20×21个整点(x,y)0≤x<20,0≤y<21,x∈Z,y∈Z),即横坐标是0到19(包含0和19)之间的整数、纵坐标是0到20(包含0和20)之间的整数的点。请问这些点一共确定了多少条不同的直线。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内将无法得分。
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
class Line implements Comparable<Line>{
double k, b;
public Line(double kk, double bb){
this.k = kk;
this.b = bb;
}
@Override
public int compareTo(Line o) {
if( Double.compare(this.k, o.k) == 0 ) return Double.compare(this.b, o.b);
return Double.compare(this.k, o.k);
}
}
public class Main{
static int N = 20, M = 21;
// static int N = 2, M = 3;
static Line[] q = new Line[1000000];
static double esp = 10E-8;
//计算斜率
public static double getK(int x1, int y1, int x2, int y2) {
return (double) (y1 - y2) /(x1 - x2) ;
}
public static void main(String[] args) {
int t = 0;
for(int i = 0; i < N; i ++) {
for(int j = 0; j < M; j ++) {
//(i, j) --> (x, y)
for(int x = 0; x < N; x ++) {
if( i == x) continue;
for(int y = 0; y < M; y ++) {
if( y == j) continue;
double k = getK(i, j, x, y);
double b = j - k * i;
q[t ++] = new Line(k, b);
}
}
}
}
//排序
Arrays.sort(q, 0, t);
int res = 1; //k :{1,1,2,2,3,3} {1,2,3}
for( int i = 1; i < t; i ++)
if( Math.abs(q[i].k - q[i - 1].k ) > esp || Math.abs(q[i].b - q[i - 1].b ) > esp)
res ++;
System.out.println(res + N + M);
}
}
import java.util.*;
public class Main {
static int gcd(int a,int b) {
return b == 0 ? a:gcd(b,a%b);
}
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
Set<String> ans = new HashSet<>();
int x = 19,y = 20;
for(int i = 0;i < x;i++) {
//将坐标以一个四位数的方式存入结合,x是百位和千位,y是十位和百位
for(int j=0;j<=y;j++) {
set.add(i*100+j);
}
}
List<Integer> arr = new ArrayList<>(set);
int len = arr.size();//坐标个数
for(int i = 0;i < len;i++) {
int a = arr.get(i);//取出一个坐标
for(int j = i+1;j < len;j++) {
int b = arr.get(j);
int x1 = a/100,x2= b/100,y1 = a%100,y2 = b%100;
int up = y1-y2,down = x1-x2;
int c1 = gcd(up,down);//求最大公约数
String k = (up/c1)+" "+(down/c1);//斜率
if(down == 0) {
ans.add("x = " + x1);//如果直线垂直与x轴则直接抛入ans集合,该情况共有19种。
continue;
}
int kb = y1*down - up*x1;
int c2 = gcd(kb,down);
String B = (kb/c2)+" "+(down/c2);//截距
ans.add(k+" "+B);
}
}
System.out.println(ans.size());
}
}
【解析】
条件定义:
给定点,求这些点之间不同的直线条数
不同直线定义:在坐标轴中不会重合成一条
构建数据结构表示不同的点:
根据给定数据我们得知x 与 y 都不会超过两位,则我们可以用一个整数表示一个点
即:int point = x * 100 + y;
构建数据结构表示直线:
在坐标轴中确定一条直线有点斜式、斜截式、两点式、截距式,这里我们使用斜截式y = kx + b来表示一条直线,实际上就是k与b确定一条直线,则k = y1- y2 / x1 - x2 , b = y1 - kx1
注意 :我们如果直接这样计算k与b的值来确定一条直线在实际上是不行的(理论可以),因为java 运算时的精度不够导致计算k与b的时候得到大于正确结果的直线数量(使用C/C++的貌似能直接AC)所以采用最简分数(两个整形数据)表示,而最终的一条直线就是由两个分数即四个整形确定,当然对于没有斜率的直线我们直接用横坐标表示。
import java.util.*;
public class Main {
public static void main(String[] args) {
List<Integer> points = new ArrayList<>();
Set<String> ans = new HashSet<>();
for(int i = 0; i < 20; i ++){
for (int j = 0; j < 21; j++) {
points.add(i * 100 + j); //存xy
}
}
int size = points.size();
for (int i = 0; i < size; i++) {
int node1 = points.get(i);
int x1 = node1 / 100, y1 = node1 % 100;
for (int j = i + 1; j < size; j++) {
int node2 = points.get(j);
int x2 = node2 / 100, y2 = node2 % 100;
int up = y1 - y2, down = x1 - x2;
if(down == 0){
ans.add("x = " + x1);
continue;
}
int c1 = gcd(up, down);
String K = up / c1 + " " + down / c1;
int Up = y1 * down - x1 * up;
int c2 = gcd(Up, down);
String B = Up/c2 + " " + down / c2;
ans.add(K + " " + B);
}
}
System.out.println(ans.size());
}
static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
}
答案:40257
4.货物摆放
【问题描述】
小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。
小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上分别堆 L、W、H 的货物,满足 n = L × W × H。
给定 n,请问有多少种堆放货物的方案满足要求。
例如,当 n = 4 时,有以下 6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2 × 2 × 1、4 × 1 × 1。
请问,当 n = 2021041820210418 (注意有 16 位数字)时,总共有多少种方案?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内将无法得分。
import java.util.*;
public class Main{
static long N = 2021041820210418L;
static List<Long> f = new ArrayList<>();
public static void main(String[] args) {
//N=4时,i = 1 2
// N/i = 4 2
for(long i = 1;i * i <= N;i++) {
if(N%i == 0) {
f.add(i);
if(N/i != i)
f.add(N/i);
}
}
long ans = 0;
for(long a:f)
for(long b:f)
for(long c:f) {
if(a * b *c ==N)
ans++;
}
System.out.println(ans);
}
}
public class Main{
private static final int max = 1010;
private static long[] a = new long[max];
public static void main(String[] args) {
long n = 2021041820210418L;
int len = 0;
//找出该数的因子
for(long i = 1;i * i <=n;i++) {
if(n%i == 0) {
a[len++]=i;
if(i != n/i) {
a[len++] = n/i;
}
}
}
long cnt = 0;//堆放方案
for(int i = 0;i < len;i++) {
for(int j = 0;j < len;j++) {
for(int k = 0;k < len;k++) {
if(a[i] * a[j] * a[k] == n) {//n=L×W×H
cnt++;
}
}
}
}
System.out.println(cnt);
}
}
答案:2430
5.路径
【问题描述】
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分
import java.util.Arrays;
public class Main{
static int N = 2200, M = N *50;//N: 点数 M:边数
static int h[] = new int [N];
static int e[] = new int [M];
static int w[] = new int [M];
static int ne[] = new int [M];
static int idx, n;
static int q[] = new int[N];
static int dist[] = new int[N];
static boolean st[] = new boolean[N];
static int INF = 0x3f3f3f3f;
public static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
public static void add(int a, int b, int c) {//添加一条边a -> b ,边的权重为c
e[idx] = b;
w[idx] = c;
ne[idx]= h[a];
h[a] = idx ++;
}
//求1号点到n号点的最短路径
public static void spfa() {
int hh = 0, tt = 0;
Arrays.fill(dist, INF);
dist[1] = 0;
q[tt ++] = 1;
st[1] = true;
while( hh != tt) {
int t = q[hh ++];
if( hh == N) hh = 0;
st[t] = false;
for(int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if( dist[j] > dist[t] + w[i]) {
dist[j] = dist[t] + w[i];
if (!st[j]) // 如果队列中已存在j,则不需要将j重复插入
{
q[tt ++ ] = j;
if (tt == N) tt = 0;
st[j] = true;
}
}
}
}
}
public static void main(String[] args) {
n = 2021;
Arrays.fill(h, - 1);
for(int i = 1; i <= n; i ++) {
for(int j = Math.max(1, i - 21); j <= Math.min(i + 21, n); j ++) {
//(i,j)节点
int d = gcd(i, j);
add(i, j, i * j / d);
}
}
spfa();
System.out.println(dist[n]);
}
}
算法思想:
Floyd算法是一个经典的动态规划算法。用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径。从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在)。从任意节点i到任意节点j的最短路径不外乎2种可能,一是直接从i到j,二是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。
public class Main {
static int[][] graph = new int[2022][2022];
static final int INF = 0x3f3f3f3f;//这个数表示无穷大
private static void floyd() {
for (int k = 1;k <= 2021;k++) {
for(int i = 1;i <= 2021;i++) {
for(int j = 1;j <= 2021;j++) {
if(i != j && graph[i][j] > graph[i][k] + graph[k][j]) {
graph[i][j] = graph[i][k] + graph[k][j];
}
}
}
}
}
private static int gcd(int a,int b) {
return b == 0 ? a : gcd(b,a%b);
}
public static void main(String[] args) {
for(int i = 1;i <= 2021;i++) {
for(int j = 1;j <= 2021;j++) {
graph[i][j] = INF;
}
}
for(int i = 1;i <= 2021;i++) {
int st = Math.max(i - 21, 1);//这么写是因为差值<=21的点之间才有直接相连的边
for(int j = st;j <= i;j++) {
int div = gcd(j,i);
int lcm = i * j / div;//无向边的大小
graph[i][j] = lcm;
graph[j][i] = lcm;
}
}
floyd();
System.out.println(graph[1][2021]);
}
}
答案:10266837
6.时间显示
【问题描述】
小蓝要和朋友合作开发一个时间显示的网站。在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 1970 年 1 月 1 日 00 : 00 : 00 到当前时刻经过的毫秒数。
现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。
给定一个用整数表示的时间,请将这个时间对应的时分秒输出。【输入格式】
输入一行包含一个整数,表示时间。
【输出格式】
输出时分秒表示的当前时间,格式形如 H H : M M : S S,其中 H H表示时,值为 0 到 23 ,M M 表示分,值为 0 到 59,S S 表示秒,值为 0 到 59 。时、分、秒不足两位时补前导 0。
【样例输入1】
46800999
【样例输出1】
13:00:00
【样例输入2】1618708103123
【样例输出2】
01:08:23
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
long n=sc.nextLong();
n/=1000;//得出秒
int day=24*60*60;//一小时的秒数
n=n%day;//求出时的秒数
int h=(int) (n/(60*60));//一分钟的秒数
n%=60*60;//求出分的秒数
int m=(int) (n/60);//一的秒数
n%=60;//求出秒的秒数
String date;
if(h>10) {
date=h+":";
}else {
date="0"+h+":";
}
if(m>10) {
date+=m+":";
}else {
date+="0"+m+":";
}
if(n>10) {
System.out.println(date+n);
}else {
System.out.println(date+"0"+n);
}
}
}
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextLong();
n -= 8*60*60*1000;
Date date = new Date(n);
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
System.out.println(format.format(date));
}
}
【注意】
用Date时要注意时区问题,我们是东8区所已一开始是1900-01-01 8:00:00
所有要减去8个小时的毫秒数。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
long nub=scanner.nextLong();
nub/=1000;
long hours=nub/60/60%60;
String hoursString=String.valueOf(hours);
long minute=nub/60%60;
String minuteString=String.valueOf(minute);
long second=nub%60;
String secondString=String.valueOf(second);
if (hours<10) {
hoursString="0"+hours;
}
if (minute<10) {
minuteString="0"+minute;
}
if (second<10) {
secondString="0"+second;
}
System.out.println(hoursString+":"+minuteString+":"+secondString);
}
}
7.最少砝码(等比数列)
【问题描述】
你有一架天平。现在你要设计一套砝码,使得利用这些砝码可以称出任意小于等于 N 的正整数重量。
那么这套砝码最少需要包含多少个砝码?
注意砝码可以放在天平两边。【输入格式】
输入包含一个正整数 N。【输出格式】
输出一个整数代表答案。【样例输入】
7【样例输出】
3【样例说明】
3 个砝码重量是 1、4、6,可以称出 1 至 7 的所有重量。
1 = 1;
2 = 6 − 4 (天平一边放 6,另一边放 4);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
少于 3 个砝码不可能称出 1 至 7 的所有重量。
结果应该是最少的砝码数量
首先,如果要称的重量为1的话,只能选择重量为1的砝码,1是必选的一个砝码。然后再称比1重的,反正都是要再加砝码,那我们为何不选一个能称的重量尽可能大的呢。
选1、2的砝码可以满足1=1,2=2,3=1+2
选1、3的砝码可以满足1=1,2=3-1,3=3,4=3+1
选1、4的砝码可以满足1=1,2=?无法称2,不合题意
因此我们选择的砝码组合是1、3,此时我们可以称的最大重量为4当我们还需要再增加砝码时
同理可得
选1、3、9的组合可以满足小于等于13(13=1+3+9)的所有重量从中可以发现一个规律,当我们需要第三个砝码是,前两个砝码(1、3)满足的最大重量已经是4了,下一个要满足的重量是5,我们遵循砝码尽可能大的原则,选择的第三个砝码的重量满足的条件是:它减去 已经可以称得的最大重量 可以得到 下一个需要称的重量。也就是weight - 4 = 5,可得weight为9
再往下推,可以得到下面的表格
砝码序号 砝码重量 总重量(可称出的最大重量) 1 1 1 2 3 4 3 9 13 4 27 40 … … … count=count+1 weight=weight*3 total=total+weight count=count+1 weight=weight*3 total=total+weight
到此已经找到规律,可以写出这道题的代码了
表格的三列分别对应了count++; //count=count+1 weight*=3; //weight=weight*3 total+=weight; //total=total+weight
其中总重量是当前所有砝码之和,因此必须先乘3,后加到总重量里,除此之外,三行代码的顺序可调换
如果想证明的话,可以发现,取第三个砝码是weight - 4 = 5,要求的下一个重量5是总重量+1,即下一个砝码重量是当前总重量*2+1,nextWeight = total * 2+1,也可以表示为要求的下一个砝码重量weight=previousTotal * 2 + 1
证明第count次增加的砝码都是3的count-1次方当count=1时,砝码只有一个,重量为1, 3 的count−1次方 =1
当count=2时,砝码组合为1、3,是首项为1,公比为3的等比数列
设count=k(k>=2)时,砝码组合是一个首项为1公比为3等比数列,末项为3的count−1次方
,则total=(3的count次方−1) /2则当count=k+1时,第k+1个砝码的重量 weight = previousTotal * 2+1 = (3的count次方−1) /2 *2+1=3的count次方
,此时砝码组合是一个首项为1,公比为3的等比数列,末项为3的count次方
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
sc.close();
int weight = 1,count = 1,total = 1;
while(total < n) {
count++;//count=count+1
weight *= 3;//weight=weight*3
total += weight;//total=total+weight
}
System.out.println(count);
}
}
8.杨辉三角形
【问题描述】
下面的图形是著名的杨辉三角形:如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:
1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, …
给定一个正整数 N,请你输出数列中第一次出现 N 是在第几个数?
【输入格式】
输入一个整数 N。
【输出格式】
输出一个整数代表答案。
【样例输入】
6
【样例输出】
13
【评测用例规模与约定】
对于 20% 的评测用例,1 ≤ N ≤ 10;
对于所有评测用例,1 ≤ N ≤ 1000000000。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
new Main().run();
}
int N;
private void run() {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
if(N == 1)
System.out.println(1);
else {
long ans = (N + 1L) * N / 2 + 2;
for(int m = 2;m < 16;m++) {
int start = m * 2,end = N;
while(start <= end) {
int mid = start + end >> 1;
if(C(mid,m) == N) {
ans = min(ans,(mid + 1L) * mid / 2 + m +1);
break;
}if (C(mid,m) > N)
end = mid - 1;
else
start = mid + 1;
}
}
System.out.println(ans);
}
}
long min(long a,long b) {
return a < b ? a : b;
}
long C(int n,int m) {
long num = 1;
for(int nm = 1;nm <= m;n--,nm++)
if((num = num * n /nm) > N)
return num;
return num;
}
}
9.双向排序
【问题描述】
给定序列 (a_1, a_2, · · · , a_n) = (1, 2, · · · , n),即 a_i =i。
小蓝将对这个序列进行 m 次操作,每次可能是将 a_1, a_2,... , a_qi降序排列,或者将a_qi,a_qi+1,⋯,a_n 升序排列。
请求出操作完成后的序列。
【输入格式】
输入的第一行包含两个整数 n,m,分别表示序列的长度和操作次数。
接下来 m 行描述对序列的操作,其中第 i 行包含两个整数 p_i, q_i 表示操作类型和参数。当 p_i = 0时,表示将 a_1, a_2, ⋅⋅⋅,a_qi 降序排列;当 p_i = 1时,表示将 a_qi , a_qi+1, ..., a_n 升序排列。
【输出格式】
输出一行,包含 n 个整数,相邻的整数之间使用一个空格分隔,表示操作完成后的序列。
【样例输入】
3 3
0 3
1 2
0 2
【样例输出】
3 1 2
【样例说明】
原数列为 (1, 2, 3)。
第 11 步后为 (3, 2, 1)。
第 22 步后为 (3, 1, 2)。
第 33 步后为 (3, 1, 2)。与第 22 步操作后相同,因为前两个数已经是降序了。
【评测用例规模与约定】
对于 30% 的评测用例,n,m≤1000;
对于 60% 的评测用例,n,m≤5000;
对于所有评测用例,1≤n,m≤100000,0≤p_i≤1,1≤q_i≤n。
import java.util.*;
public class Main {
static int N = 100010;
static CII stk[] = new CII[N];
static int a[] = new int [N];
static int top;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//序列的长度
int m = sc.nextInt();//操作次数
while(m-- > 0) {
int t = sc.nextInt();
int x = sc.nextInt();
if(t == 0) {
while(top > 0 && stk[top].t ==0)
x = Math.max(x, stk[top --].x);
while(top >= 2 && stk[top-1].x <= x)
top -=2;
stk[++top] = new CII(0,x);
}
else if(top != 0) {
while(stk[top].t == 1)
x = Math.min(x, stk[top--].x);
while(top >= 2 && stk[top-1].x >= x)
top -=2;
stk[++top] = new CII(1,x);
}
}
int l = 1,r = n,k = n;
for(int i = 1;i <= top;i++) {
int x = stk[i].x;
if(stk[i].t == 0) {
while(r > x && l <= r)
a[r--] = k--;
}else {
while(l < x && l <= r)
a[l++] = k--;
}
if(l > r)
break;
}
if(top % 2 == 1)
while(l <= r)
a[l++] = k--;
else
while(l <= r)
a[r--] = k--;
for(int i = 1;i <= n;i++)
System.out.println(a[i] + " ");
}
static class CII{
int t,x;
public CII(int a,int b) {
t = a;
x = b;
}
}
}
10.括号序列
【问题描述】
给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果,请问有多少种本质不同的添加结果。
两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括号。
例如,对于括号序列 (((),只需要添加两个括号就能让其合法,有以下几种不同的添加结果:()()()、()(())、(())()、(()()) 和 ((()))。
【输入格式】
输入一行包含一个字符串 s,表示给定的括号序列,序列中只有左括号和右括号。
【输出格式】
输出一个整数表示答案,答案可能很大,请输出答案除以 1000000007 (即 10^9+7) 的余数。
【样例输入】
((()
【样例输出】
5
【评价用例规模与约定】
对于 40% 的评测用例,|s|≤200。 对于所有评测用例,1≤|s|≤5000。
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Main{
static Set<String> set = new HashSet<>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int left = 0;
int right = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
left++;
} else {
right++;
}
}
//int count = Math.max(left, right);
int count;//最多的括号数量
int sub;//插入的括号不能超过sub个,也就是不一样的括号数量
if (left > right) {
count = left;
sub = left - right;
} else {
count = right;
sub = right - left;
}
String temp = "";
for (int i = 0; i < count; i++) {
temp += "()";
}
dfs(temp);
int resCount = 0;
for (String s1 : set) {
int i = 0;
int j = 0;
boolean isMatch = true;
while (i < s.length() && j < s1.length()) {
int tempCount = sub;
if (s.charAt(i) == s1.charAt(j)) {
i++;
j++;
} else {
j++;
tempCount--;
}
if (tempCount < 0) {
isMatch = false;
break;
}
}
if (isMatch) {
resCount++;
}
}
System.out.println(resCount);
}
private static void dfs(String temp) {
set.add(temp);
for (int i = 0; i < temp.length() - 1; i++) {
if (temp.charAt(i) == ')' && temp.charAt(i + 1) == '(') {
String temps = temp.substring(0, i) + "()" + temp.substring(i + 2, temp.length());
dfs(temps);
}
}
}
}