problem1 link
直接模拟即可。
import java.util.*; import java.math.*; import static java.lang.Math.*; public class Dating { static boolean sametype(char c1,char c2) { return 'a'<=c1&&c1<='z'&&'a'<=c2&&c2<='z' ||'A'<=c1&&c1<='Z'&&'A'<=c2&&c2<='Z'; } public String dates(String circle, int k) { StringBuilder builder=new StringBuilder(); int startIndex=0; while(true) { boolean lower=false; boolean upper=false; for(int i=0;i<circle.length();++i) { char c=circle.charAt(i); if('a'<=c&&c<='z') { lower=true; } else { upper=true; } if(lower&&upper) { break; } } if(!lower||!upper) { break; } for(int i=0;i<k-1;++i) { ++startIndex; if(startIndex==circle.length()) { startIndex=0; } } int chooseIndex=-1; for(int i=0;i<circle.length();++i) { if(i==startIndex) { continue; } char c1=circle.charAt(i); char c2=circle.charAt(startIndex); if(!sametype(c1,c2)) { if(chooseIndex==-1||circle.charAt(chooseIndex)>c1) { chooseIndex=i; } } } if(builder.length()>0) { builder.append(" "); } builder.append(circle.charAt(startIndex)).append(circle.charAt(chooseIndex)); if(chooseIndex<startIndex) { circle=circle.substring(0,chooseIndex)+ circle.substring(chooseIndex+1,startIndex)+ circle.substring(startIndex+1); startIndex-=1; if(startIndex==circle.length()) { startIndex=0; } } else { circle=circle.substring(0,startIndex)+ circle.substring(startIndex+1,chooseIndex)+ circle.substring(chooseIndex+1); if(startIndex==circle.length()) { startIndex=0; } } } return builder.toString(); } }
problem2 link
设$h(x)$表示$[1,x]$范围内有多少符合要求的数字,那么题意就是计算$h(high)-h(low-1)$。
对于$h(n)$来说,设$n$有$d$位数字,$f(x)(y)(z)$表示已经考虑的数字的高$x$位,$y$表示已经考虑的数字中跟$n$的高$x$位相等还是小于还是已经考虑的高$x$位都是0,三种情况;$y$表示前一位数字是多少。
import java.util.*; import java.math.*; import static java.lang.Math.*; public class JumpyNum { int[][][] f=null; int[] digit=null; int dfs(int d,int tag,int pre) { if(d<0) { return tag==2?0:1; } if(f[d][tag][pre]!=-1) { return f[d][tag][pre]; } int result=0; for(int i=0;i<10;++i) { if(tag==0) { if(Math.abs(i-pre)>=2) { result+=dfs(d-1,0,i); } } else if(tag==1) { if(i<=digit[d]&&Math.abs(i-pre)>=2) { result+=dfs(d-1,i==digit[d]?1:0,i); } } else { result+=dfs(d-1,i==0?2:0,i); } } return f[d][tag][pre]=result; } int cal(int n) { if(n<10) { return n; } int d=String.valueOf(n).length(); digit=new int[d]; for(int i=0;i<d;++i) { digit[i]=n%10; n/=10; } f=new int[d][3][10]; for(int i=0;i<d;++i) { for(int j=0;j<3;++j) { for(int k=0;k<10;++k) { f[i][j][k]=-1; } } } int result=0; for(int i=0;i<=digit[d-1];++i) { if(i==0) { result+=dfs(d-2,2,0); } else { result+=dfs(d-2,i==digit[d-1]?1:0,i); } } return result; } public int howMany(int low, int high) { return cal(high)-cal(low-1); } }
problem3 link
首先求出与$x$轴的所有交点,然后每两个相邻交点的中间的范围都有可能被绕过若干圈(如果它不在外部或者边上)。这时可以取中间值进行计算。
对于某个点,将其与每条边的两个端点连线,计算转过的角度即可。如果在外部,那么转过的总角度是0,在内部一定是$2pi$的若干倍。
对于两个向量$vec{a},vec{b}$,可以用$arctan(t)$来计算转角,其中$t=frac{cross(vec{a},vec{b})}{dot(vec{a},vec{b})}$。因为$frac{dot(vec{a},vec{b})}{|vec{a}|}$表示$vec{b}$在$vec{a}$上的投影长度,$frac{cross(vec{a},vec{b})}{|vec{a}|}$表示以$vec{a},vec{b}$为边的平行四边形的高(面积除以底边长),所以它们的比值就是转角的正切值。
import java.util.*; import java.math.*; import static java.lang.Math.*; class point { public double x; public double y; public point(){} public point(double x,double y) { this.x=x; this.y=y; } public double crossMultiply(point a) { return x*a.y-y*a.x; } public point substract(point a) { return new point(x-a.x,y-a.y); } public double dotMultiply(point a) { return x*a.x+y*a.y; } public double calculateAngle(point a) { return Math.atan2(crossMultiply(a),dotMultiply(a)); } public void print() { System.out.println("x="+x+", y="+y); } }; public class AllWoundUp { static int cal(double t,int[] px,int[] py) { double sum=0; final int n=px.length; for(int i=0;i<n;++i) { int x0=px[i],y0=py[i]; int x1=px[(i+1) % n],y1=py[(i+1)%n]; if(y0==y1&&y0==0) { continue; } sum+=new point(x0-t,y0).calculateAngle(new point(x1-t,y1)); } return (int)(sum/2/Math.PI+0.5); } public int maxWind(int[] x, int[] y) { List<Double> list=new ArrayList<>(); final int n=x.length; for(int i=0;i<n;++i) { int x0=x[i],y0=y[i]; int x1=x[(i+1)%n],y1=y[(i+1)%n]; if(y0==y1) { continue; } if(x0==x1) { if(y0*y1<=0) { list.add((double)x0); } continue; } if(y0*y1>0) { continue; } double k=1.0*(y0-y1)/(x0-x1); list.add(-y0/k+x0); } Collections.sort(list); int result=0; for(int i=1;i<list.size();++i) { if(Math.abs(list.get(i)-list.get(i-1))<1e-10) { continue; } double t=(list.get(i)+list.get(i-1))/2; boolean tag=false; for(int j=0;j<n;++j) { int x0=x[j],y0=y[j]; int x1=x[(j+1)%n],y1=y[(j+1)%n]; if(y0==y1&&y0==0&&Math.min(x0,x1)<=t&&t<=Math.max(x0,x1)) { tag=true; break; } } if(tag) { continue; } result=Math.max(result,cal(t,x,y)); } return result; } }