目录
1.ASC
2.卡片
3.直线
4.货物摆放
5.路径
6.时间显示
7.最少砝码
8.杨辉三角形
9.双向排序
10.括号序列
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=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) {doif(++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{double k, b;public Line(double kk, double bb){this.k = kk;this.b = bb;}@Overridepublic 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 set = new HashSet<>();Set 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 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 points = new ArrayList<>();Set 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 f = new ArrayList<>();public static void main(String[] args) {//N=4时,i = 1 2// N/i = 4 2for(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×Hcnt++;}}}}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 ,边的权重为ce[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+1weight *= 3;//weight=weight*3total += 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;elsestart = 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--;elsewhile(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 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);}}}
}
