problem1 link
二分答案,然后计算总时间。跟$T$比较确定要增大答案还是减小答案。
problem2 link
可以看作是以‘*’所在位置为根的树。所以每个非根节点都有一个父节点。
那么每个非根结点$x$都可以表示其根结点$y$的函数,,类型为$x=p+qy$。比如说有三个节点$x,y,z$,$y$是$x$的父节点,$z$是$y$的父节点,那么有$x=1+y,y=1+\frac{1}{2}(x+z)=1+\frac{1}{2}(1+y+z)\rightarrow y=3+z$。也就是说,这可以从每个叶子结点自底向上从而确定每个节点与其父节点的函数关系。
最后由于根结点的值为0,然后自顶向下可以确定每个节点的值。
problem3 link
首先,假设$n=500$时,squaer-free数字大约有$m\approx 300$个,所以$K$大于$m$时,可以直接令$K=m$。
其次,当一个质数$t>\sqrt{500}=22.3$时,如果它是某一个squaer-free的质因子,那么它一定是这个squaer-free 最大的质因子。而小于$22$的质因子只有8个$(2,3,5,7,11,13,17,19)。
所以可以进行动态规划。首先将所有的squaer-free数字按照即其最大质因子升序排序。$f(i,mask,k,flag)$表示已经已经考虑了前$i$个squaer-free数字,含有的小于$22$的质因子的状态为$mask$,含有的大于$22$的质因子的最大一个质因子的状态为$tag$(=0 or 1),已经选择了$k$个的方案数。
那么对于每次新选择的一个数字$t$,其含有的小于$22$的质因子状态$m_{t}$&$mask$应该等于0,同时假设其含有的最大质因子大于$22$,那么上一个选择的数字含有的最大质因子应该小于$t$含有的最大质因子。
code for problem1
import java.util.*;
import java.math.*;
import static java.lang.Math.*;
public class IncredibleMachine {
public double gravitationalAcceleration(int[] x, int[] y, int T) {
double low=0,high=100000;
for(int i=0;i<100;++i) {
double mid=(low+high)*0.5;
if(cal(mid,x,y)>T) {
low=mid;
}
else {
high=mid;
}
}
return low;
}
double cal(double g,int[] x,int[] y) {
double v=0;
double t=0;
for(int i=1;i<x.length;++i) {
double[] tmp=get(v,g,x[i-1],y[i-1],x[i],y[i]);
t+=tmp[0];
v+=tmp[1]*tmp[0];
}
return t;
}
double[] get(double v0,double g,int x0,int y0,int x1,int y1) {
double d=Math.sqrt((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1));
double a=g*((y0-y1)/d);
double t=Math.sqrt((v0*v0+2*d*a)/(a*a))-v0/a;
return new double[]{t,a};
}
}
code for problem2
import java.util.*;
import java.math.*;
import static java.lang.Math.*;
public class MazeWandering {
static class FatherInfo {
double fx,fy;
double p,q;
FatherInfo() {}
FatherInfo(int fx,int fy,double p,double q) {
this.fx=fx;
this.fy=fy;
this.p=p;
this.q=q;
}
}
double[][] result=null;
FatherInfo[][] fatherInfos=null;
String[] maze=null;
int n,m;
int[] dx={0,0,1,-1};
int[] dy={1,-1,0,0};
int tx,ty;
public double expectedTime(String[] maze) {
this.maze=maze;
n=maze.length;
m=maze[0].length();
result=new double[n][m];
fatherInfos=new FatherInfo[n][];
for(int i=0;i<n;++i) {
fatherInfos[i]=new FatherInfo[m];
}
tx=-1;
for(int i=0;i<n&&tx==-1;++i) {
for(int j=0;j<m&&tx==-1;++j) {
if(maze[i].charAt(j)=='*') {
tx=i;
ty=j;
}
}
}
fatherInfos[tx][ty]=new FatherInfo(-1,-1,0,0);
for(int i=0;i<4;++i) {
int xx=tx+dx[i];
int yy=ty+dy[i];
if(check(xx,yy)) {
dfs(xx,yy,tx,ty);
}
}
Queue<Integer> queue=new LinkedList<>();
queue.offer(tx*100+ty);
result[tx][ty]=0;
while(!queue.isEmpty()) {
int x=queue.peek()/100;
int y=queue.peek()%100;
queue.poll();
for(int i=0;i<4;++i) {
int xx=x+dx[i];
int yy=y+dy[i];
if(check(xx,yy)&&(xx!=fatherInfos[x][y].fx||yy!=fatherInfos[x][y].fy)) {
result[xx][yy]=fatherInfos[xx][yy].p+fatherInfos[xx][yy].q*result[x][y];
queue.offer(xx*100+yy);
}
}
}
double sum=0;
int cnt=0;
for(int i=0;i<n;++i) {
for(int j=0;j<m;++j) {
if(maze[i].charAt(j)!='X') {
sum+=result[i][j];
++cnt;
}
}
}
return sum/cnt;
}
boolean check(int xx,int yy) {
return xx>=0&&xx<n&&yy>=0&&yy<m&&maze[xx].charAt(yy)=='.';
}
double[] dfs(int x,int y,int fx,int fy) {
List<double[]> list=new ArrayList<>();
for(int i=0;i<4;++i) {
int xx=x+dx[i];
int yy=y+dy[i];
if(check(xx,yy)&&(xx!=fx||yy!=fy)) {
list.add(dfs(xx,yy,x,y));
}
}
if(list.size()==0) {
fatherInfos[x][y]=new FatherInfo(fx,fy,1,1);
return new double[]{1,1};
}
double p=0,q=0;
for(int i=0;i<list.size();++i) {
p+=list.get(i)[0];
q+=list.get(i)[1];
}
double r0=(1+list.size()+p)/(1+list.size()-q);
double r1=1.0/(1+list.size()-q);
fatherInfos[x][y]=new FatherInfo(fx,fy,r0,r1);
return new double[]{r0,r1};
}
}
code for problem3
import java.util.*;
import java.math.*;
import static java.lang.Math.*;
public class SquareFreeSets {
static final int MOD=1000000007;
List<Integer> primes=new ArrayList<>();
public int countPerfect(int N, int K) {
for(int i=2;i<=N;++i) {
if(isPrime(i)) {
primes.add(i);
}
}
List<Integer> all=new ArrayList<>();
List<Integer> bitmask=new ArrayList<>();
int[] maxPrime=new int[N+1];
for(int i=2;i<=N;++i) {
if(check(i)) {
all.add(i);
maxPrime[i]=calMaxPrime(i);
}
}
Collections.sort(all, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
if(maxPrime[o1]<maxPrime[o2]) {
return -1;
}
if(maxPrime[o1]==maxPrime[o2]) {
return o1<o2?-1:1;
}
return 1;
}
});
for(int i=0;i<all.size();++i) {
bitmask.add(getBitmask(all.get(i)));
}
int[][][][] f=new int[2][1<<8][K+1][2];
int pre=0;
int cur=1;
f[0][bitmask.get(0)][1][0]=1;
f[0][0][0][0]=1;
for(int i=1;i<all.size();++i) {
for(int x=0;x<(1<<8);++x) {
for(int y=0;y<K+1;++y) {
for(int z=0;z<2;++z){
f[cur][x][y][z]=0;
}
}
}
for(int j=0;j<(1<<8);++j) {
for(int k=0;k<K+1;++k) {
for(int t=0;t<2;++t) {
final int v=f[pre][j][k][t];
if(v==0) {
continue;
}
int newt=(maxPrime[all.get(i)]!=maxPrime[all.get(i-1)]||maxPrime[all.get(i)]<20)?0:t;
f[cur][j][k][newt]+=v;
if(f[cur][j][k][newt]>=MOD) {
f[cur][j][k][newt]-=MOD;
}
if(t==1&&maxPrime[all.get(i)]>20&&maxPrime[all.get(i)]==maxPrime[all.get(i-1)]) {
continue;
}
if((bitmask.get(i)&j)!=0) {
continue;
}
if(k+1>K) {
continue;
}
newt=maxPrime[all.get(i)]>20?1:0;
f[cur][j|bitmask.get(i)][k+1][newt]+=v;
if(f[cur][j|bitmask.get(i)][k+1][newt]>=MOD) {
f[cur][j|bitmask.get(i)][k+1][newt]-=MOD;
}
}
}
}
pre^=1;
cur^=1;
}
int result=0;
for(int j=0;j<(1<<8);++j) {
for(int k=1;k<=K;++k) {
for(int t=0;t<2;++t) {
result+=f[pre][j][k][t];
if(result>=MOD) {
result-=MOD;
}
}
}
}
return result;
}
int getBitmask(int x) {
int result=0;
if(x%2==0) {
result|=1;
}
if(x%3==0) {
result|=2;
}
if(x%5==0) {
result|=4;
}
if(x%7==0) {
result|=8;
}
if(x%11==0) {
result|=16;
}
if(x%13==0) {
result|=32;
}
if(x%17==0) {
result|=64;
}
if(x%19==0) {
result|=128;
}
return result;
}
int calMaxPrime(int x) {
for(int i=primes.size()-1;i>=0;--i) {
if(x%primes.get(i)==0) {
return primes.get(i);
}
}
return 1;
}
boolean isPrime(int x){
for(int i=2;i*i<=x;++i) {
if(x%i==0) {
return false;
}
}
return true;
}
boolean check(int x) {
for(int i=0;primes.get(i)*primes.get(i)<=x;++i) {
if(x%primes.get(i)==0&&x%(primes.get(i)*primes.get(i))==0) {
return false;
}
}
return true;
}
}