topcoder srm 340 div1
problem1 link
$f[i][L][R]$表示计算到第$i$个,最小最大值是$L,R$时的最少个数。
import java.util.*; import java.math.*; import static java.lang.Math.*; public class ProblemsToSolve { int[] unique(int[] p) { int n=p.length; int[] a=new int[n]; for(int i=0;i<n;++i) { a[i]=p[i]; } Arrays.sort(a); int id=0; for(int i=1;i<n;++i) { if(a[i]!=a[id]) { a[++id]=a[i]; } } ++id; if(id==n) { return a; } int[] q=new int[id]; for(int i=0;i<id;++i) { q[i]=a[i]; } return q; } int getindex(int[] p,int x) { for(int i=0;i<p.length;++i) { if(p[i]==x) { return i; } } return -1; } public int minNumber(int[] p,int variety) { final int n=p.length; final int[] a=unique(p); final int m=a.length; int[][][] f=new int[n][m][m]; for(int i=0;i<n;++i) { p[i]=getindex(a,p[i]); } int result=n; for(int i=0;i<n;++i) { for(int j=0;j<m;++j) { for(int k=0;k<m;++k) { f[i][j][k]=-1; } } } f[0][p[0]][p[0]]=1; for(int i=1;i<n;++i) { for(int j=i-1;j>=i-2&&j>=0;--j) { for(int x=0;x<m;++x) { for(int y=x;y<m;++y) { if(f[j][x][y]==-1) continue; if(p[i]>y) { if(a[p[i]]-a[x]>=variety) { result=Math.min(result,f[j][x][y]+1); continue; } } else if(p[i]<x) { if(a[y]-a[p[i]]>=variety) { result=Math.min(result,f[j][x][y]+1); continue; } } final int nx=Math.min(x,p[i]); final int ny=Math.max(y,p[i]); if(f[i][nx][ny]==-1||f[i][nx][ny]>f[j][x][y]+1) { f[i][nx][ny]=f[j][x][y]+1; } } } } } return result; } }
problem2 link
$f[i][j]$表示两个分数分别达到$i,j$时选择的最少课程数,并记录选择的课程是哪些。这样进行bfs即可。
import java.util.*; import java.math.*; import static java.lang.Math.*; public class CsCourses { String int2string(int x) { if(x<10) { return "0"+Integer.toString(x); } return Integer.toString(x); } public int[] getOrder(int[] t, int[] p, int[] e, int skillBound) { if(skillBound==0) { return new int[0]; } final int n=t.length; int[][] f=new int[51][51]; String[][] d=new String[51][]; boolean[][] inq=new boolean[51][51]; for(int i=0;i<51;++i) { d[i]=new String[51]; for(int j=0;j<51;++j) { f[i][j]=-1; inq[i][j]=false; } } Queue<Integer> que=new LinkedList<>(); for(int i=0;i<n;++i) { if(t[i]<=1&&p[i]<=1&&e[i]>=1&&t[i]+p[i]>0&&f[t[i]][p[i]]==-1) { f[t[i]][p[i]]=1; d[t[i]][p[i]]=int2string(i); que.offer(t[i]*100+p[i]); inq[t[i]][p[i]]=true; } } while(!que.isEmpty()) { final int ii=que.peek()/100; final int jj=que.peek()%100; que.poll(); if(ii>=skillBound&&jj>=skillBound) { continue; } for(int k=0;k<n;++k) { if(t[k]<=ii&&p[k]<=jj) continue; if(t[k]-ii>1) continue; if(p[k]-jj>1) continue; if(e[k]<=f[ii][jj]) continue; final int nii=Math.max(ii,t[k]); final int njj=Math.max(jj,p[k]); if(f[nii][njj]==-1 ||f[nii][njj]>f[ii][jj]+1 ||f[nii][njj]==f[ii][jj]+1 &&0<d[nii][njj].compareTo(d[ii][jj]+","+int2string(k))) { f[nii][njj]=f[ii][jj]+1; d[nii][njj]=d[ii][jj]+","+int2string(k); if(!inq[nii][njj]) { que.offer(nii*100+njj); inq[nii][njj]=true; } } } } int num=Integer.MAX_VALUE; String route=""; for(int i=skillBound;i<51;++i) { for(int j=skillBound;j<51;++j) { if(f[i][j]!=-1&&f[i][j]<num||f[i][j]==num&&d[i][j].compareTo(route)<0) { num=f[i][j]; route=d[i][j]; } } } if(num==Integer.MAX_VALUE) { return new int[0]; } String[] path=route.split(","); int[] result=new int[path.length]; for(int i=0;i<path.length;++i) { result[i]=Integer.valueOf(path[i]); } return result; } }
problem3 link
判断一个点在多边形的内部还是外部可以用射线法。一条从某一点发出的射线与多边形有奇数个交点则在内部。
初始时认为每个格子有个垂直向上的射线。每次横着走时,下面的所有格子与多边形的交点个数增加了1.
$f[x][y][mask]$表示从$(0,0)$走到$(x,y)$,经过的$'I'$或者$'X'$的状态是$mask$的最短路。
import java.util.*; import java.math.*; import static java.lang.Math.*; public class VegetableGarden { public int[] getMinDistances(String[] g) { final int n = g.length; final int m = g[0].length(); int id = 0; int badMask=0; int iNum=0; List<Integer> list=new ArrayList<>(); for(int i=0;i<n;++i) { for(int j=0;j<m;++j) { if(g[i].charAt(j)!='.') { if(g[i].charAt(j)=='X') { badMask|=1<<id; } else { ++iNum; } list.add(i*100+j); ++id; } } } int[][][] f=new int[n+1][m+1][1<<id]; boolean[][][] inq=new boolean[n+1][m+1][1<<id]; for(int i=0;i<n+1;++i) { for(int j=0;j<m+1;++j) { for(int k=0;k<(1<<id);++k) { f[i][j][k]=-1; inq[i][j][k]=false; } } } Queue<Integer> queue=new LinkedList<>(); f[0][0][0]=0; inq[0][0][0]=true; queue.offer(0); final int[] dx={0,1,0,-1}; final int[] dy={1,0,-1,0}; while(!queue.isEmpty()) { final int mask=queue.peek()/10000; final int x=queue.peek()%10000/100; final int y=queue.peek()%100; queue.poll(); inq[x][y][mask]=false; for(int d=0;d<4;++d) { final int xx=x+dx[d]; final int yy=y+dy[d]; if(xx<0||yy<0||xx>=n+1||yy>=m+1) continue; int nMask=mask; if(d==0||d==2) { final int column=d==0?y:y-1; for(int k=0;k<list.size();++k) { final int nx=list.get(k)/100; final int ny=list.get(k)%100; if(ny==column&&nx>=x) { nMask^=1<<k; } } } if(f[xx][yy][nMask]==-1||f[xx][yy][nMask]>f[x][y][mask]+1) { f[xx][yy][nMask]=f[x][y][mask]+1; if(!inq[xx][yy][nMask]) { inq[xx][yy][nMask]=true; queue.offer(nMask*10000+xx*100+yy); } } } } int[] result=new int[iNum]; for(int i=0;i<(1<<id);++i) { if((i&badMask)!=0) continue; if(f[0][0][i]==-1) continue; int c=0; int k=i; while(k!=0) { c+=k&1; k>>=1; } if(c==0) { continue; } if(result[c-1]==0||result[c-1]>f[0][0][i]) { result[c-1]=f[0][0][i]; } } return result; } }