HIST ICPC校内选拔训练赛(纯思维题)
A.Almost Rectangle
思路:题目大概意思是在二维矩阵里给出你两个点,有可能在同一行同一列,然后让你枚举出另外两个点,使他们成为一个矩形。这里除了需要特判的同一行同一列,要考虑边界情况外,其余都是
ch[x1][y2],ch[x2][y1]
。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while(t-->0) {
int n = sc.nextInt();
sc.nextLine();
char ch[][] = new char[n][n];
boolean flag = false;
int x1=0,x2=0,y1=0,y2=0;
for(int i=0;i<n;i++) {
ch[i] = sc.nextLine().toCharArray();
}
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
if(!flag&&ch[i][j]=='*') {
x1 = i;y1 = j;
flag = true;
}
if(flag&&ch[i][j]=='*') {
x2 = i;y2 = j;
}
}
}
if(x1==x2) {
ch[x1==n-1?n-2:x1+1][y1] = '*';
ch[x2==n-1?n-2:x2+1][y2] = '*';
}else if(y1==y2) {
ch[x1][y1==n-1?n-2:y1+1] = '*';
ch[x2][y2==n-1?n-2:y1+1] = '*';
}else {
ch[x2][y1]='*';
ch[x1][y2]='*';
}
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
System.out.print(ch[i][j]);
}System.out.println();
}
}
}
}
B.A-B Palindrome
这题我将近写了90行,就是模拟,需要特殊考虑将序列变为对称后,“?”的个数是奇数的情况
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while(t-->0) {
int a = sc.nextInt();
int b = sc.nextInt();
sc.nextLine();
char arr[] = sc.nextLine().toCharArray();
if(a+b!=arr.length) {
System.out.println(-1);
continue;
}
int index =0;
int n = arr.length;
for(int i=0;i<arr.length;i++) {
if(arr[i]=='?') index++; //记录?个数
if(arr[i]=='0')a--;
if(arr[i]=='1')b--;
}
for(int i=0;i<n;i++) {
if(arr[i]!='?'&&arr[n-i-1]=='?') {
if(arr[i]=='0') {
arr[n-i-1]='0';a--;index--;
}
if(arr[i]=='1') {
arr[n-i-1]='1';b--;index--;
}
}
if(arr[i]=='?'&&arr[n-i-1]!='?') {
if(arr[n-i-1]=='0') {
arr[i]='0';a--;index--;
}
if(arr[n-i-1]=='1') {
arr[i]='1';b--;index--;
}
}
}
if(index%2==0&&a%2!=0&&b%2!=0) {
System.out.println(-1);
continue;
}else {
if(index%2!=0) {
arr[n/2]=a%2!=0?'0':'1';
if(a%2!=0)a--;else b--;
index--;
}
for(int i=0;i<n&&a>0;i++) {
if(arr[i]=='?') {
arr[i]='0';
arr[n-i-1]='0';
a-=2;
}
}
for(int i=0;i<n&&b>0;i++) {
if(arr[i]=='?'){
arr[i]='1';
arr[n-i-1]='1';
b-=2;
}
}
}
boolean flag = false;
for(int i=0;i<n;i++) {
if(arr[i]!=arr[n-i-1]) {
flag = true;
System.out.println(-1);
break;
}
}
if(!flag&&(a<0||b<0)) {
System.out.println(-1);
flag = true;
continue;
}
if(!flag) {
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]);
}
if(t!=0)System.out.println();
}
}
}
}
C.Corrupted Array
满足条件的可以分为3中情况
1.前n项和Sn=b[n]
2.前n项和Sn=b[n+1]
3.前n+1项和Sn+1-a[i]=b[n+1]
这里的a[i]要通过遍历得出
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while(t-->0) {
int n = sc.nextInt();
Long b[] = new Long[n+2];
long s1 = 0;//前n项和
for(int i=0;i<n+2;i++) {
b[i] = sc.nextLong();
}
Arrays.sort(b);
for(int i=0;i<n;i++) {
s1+=b[i];
}
if(s1==b[n]||s1==b[n+1]) {
System.out.print(b[0]);
for(int i=1;i<n;i++) {
System.out.print(" "+b[i]);
}
System.out.println();
}else {
s1+=b[n];
int index=n;
for(int i=0;i<=n;i++) {
if(s1-b[i]==b[n+1]) {
index = i;
}
}
if(index==n)System.out.println(-1);
else {
for(int i=0;i<n;i++) {
if(i!=index) {
System.out.print(b[i]+" ");
}
}
System.out.print(b[n]);
System.out.println();
}
}
}
}
}
D.Double-ended Strings
这道题使求最大连续公共子序列,假设最大连续公共子序列长度为x,则答案为
(a.length()+b.length())-max*2
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
sc.nextLine();
while(n-->0) {
String a = sc.nextLine();
String b = sc.nextLine();
if(a.length()<b.length()) {
String t = a;
a = b;
b = t;
}
int max = Integer.MIN_VALUE;
for(int i=0;i<a.length();i++) {
for(int j=0;j<b.length();j++) {
int k = 0;
while(i+k<a.length()&&j+k<b.length()&&a.charAt(i+k)==b.charAt(j+k)) {
k++;
}
max = Math.max(max,k);
}
}
System.out.println((a.length()+b.length())-max*2);
}
}
}
E.Binary Removals
这个我没过
F.Spy Detected!
一个序列中只有一个数的与其他数不同,我用的是sort排序,不是在开头就是在结尾
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while(t-->0) {
int n = sc.nextInt();
int arr[] = new int[n];
int b[] = new int[n];
for(int i=0;i<n;i++) {
arr[i] = sc.nextInt();
}
b=arr.clone();
Arrays.sort(b);
int x;
if(b[0]==b[1])x=b[n-1];
else x=b[0];
for(int i=0;i<arr.length;i++) {
if(arr[i]==x) {
System.out.println(i+1);
break;
}
}
}
}
}
G.The Great Hero
这个emm没写出来
H.Ping-pong
这一道题分析一下即可,题目中说,他们为了使自己得分最大化,都会采用最佳策略,分析可知,Alice先发球,如果Bob不接,Alice赢,接下来Alice还会发球,等Alice最后一次发球时,Bob开始反击。接下来Bob还剩余几个耐力就可以赢一场,这样来说两者的胜场都是最大的。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
while(n-->0) {
int x = sc.nextInt();
int y = sc.nextInt();
System.out.println(x-1+" "+y);
}
}
}
I.Increase and Copy
大意:初始给你一个元素 1,每次操作你可以选择让一个元素 +1 或者复制出元素.求最少需要多少次操作使其总和不小于 n .
思路:因为不用考虑恰好到达n,所以最后一步用复制肯定是最快的。
1.假如 n \sqrt{n} n刚好是整数,那么复制 n \sqrt{n} n肯定是最优的
2.假如 n \sqrt{n} n不是整数,那么如果 n \sqrt{n} n* n + 1 \sqrt{n+1} n+1>=n,如果这个满足,就用这个式子。3.如果 n \sqrt{n} n* n + 1 \sqrt{n+1} n+1<n,那么只能用 n + 1 \sqrt{n+1} n+1 n + 1 \sqrt{n+1} n+1
接下来还要考虑一个东西,那就是分解完第一步,剩下的是加最优呢,还是复制与加一起用最优呢?
1.如果用加得到,那么只需要加大概 n \sqrt{n} n次即可
2.如果用复制得到,则远远大于 n \sqrt{n} n
举个例子;比如n=169*169,通过上述可知先得到169然后再复制168次即可。如果只用加法,那么需要进行169-1次 。(总共168+168次)
如果加法复制都用,先用加法得到一个13,进行了12次。接下来13要经过12次复制,得到169.接下来,169要进行复制,但是这个169是由13个13组成的,也就是要将13个13复制168次,也就是13169次。(共12+13+13169)。所以复制一次就是最优的选择。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while(t-->0) {
int n = sc.nextInt();
int m = (int)Math.sqrt(n);
if(m*m==n)System.out.println(m-1+m-1);
else {
if(m*(m+1)>=n) {
System.out.println(m-1+m);
}else {
System.out.println(m+m);
}
}
}
}
}