problem1 link

$g[i]$表示解决前$i$个的代价,那么$g[i]$是所有$g[j]+cost(j+1,i)$的最小值。

import java.util.*;
import java.math.*;
import static java.lang.Math.*;

public class FenceRepairing {
	
	public double calculateCost(String[] boards) {
		StringBuilder builder=new StringBuilder();
		for(int i=0;i<boards.length;++i) {
			builder.append(boards[i]);
		}

		final String s=builder.toString();
		final int n=s.length();
		int[] f=new int[n+1];
		f[0]=0;
		for(int i=1;i<=n;++i) {
			f[i]=f[i-1];
			if(s.charAt(i-1)=='X') {
				++f[i];
			}
		}
		double[] g=new double[n+1];
		g[0]=0;
		for(int i=1;i<=n;++i) {
			g[i]=g[i-1];
			if(f[i]-f[i-1]!=0) {
				g[i]+=1;
			}
			for(int j=0;j<i;++j) {
				double t=g[j];
				if(f[i]-f[j]>0) {
					t+=Math.sqrt(i-j);
				}
				if(t<g[i]) {
					g[i]=t;
				}
			}
		}
		return g[n];
	}
}

problem2 link

分别讨论$X$的取值区间即可。

import java.util.*;
import java.math.*;
import static java.lang.Math.*;

public class ModularInequality {

	
	public int countSolutions(int[] A, int P) {
		Arrays.sort(A);
		int result=0;
		final int n=A.length;
		long sum=0;
		for(int x:A) {
			sum+=x;
		}


		if(sum>=P) {
			long k=(sum-P+n-1)/n;
			if(k<A[0]) {
				result+=A[0]-k;
			}
		}
		else {
			long k=(sum-P)/n;
			if(k<A[0]) {
				result+=A[0]-k;
			}
		}

		if(P+sum>=0) {
			long k=(P+sum)/n;
			if(A[n-1]<=k) {
				result+=k-A[n-1]+1;
			}
		}
		else {
			long k=(P+sum-(n-1))/n;
			if(A[n-1]<=k) {
				result+=k-A[n-1]+1;
			}
		}

		long pre=0;
		for(int i=1;i<n;++i) {
			pre+=A[i-1];
			sum-=A[i-1];

			if(A[i]==A[i-1]) {
				continue;
			}

			long aa=P-(sum-pre);
			long bb=i+i-n;

			if(bb==0) {
				if(aa>=0) {
					result+=A[i]-A[i-1];
				}
			}
			else if(bb<0) {
				long k=-1;
				if(aa<0) {
					k=aa/bb;
					if(aa%bb!=0) {
						++k;
					}
				}
				else if(aa==0) {
					k=0;
				}
				else {
					k=aa/bb;
				}
				if(k<A[i]) {
					result+=A[i]-Math.max(A[i-1],k);
				}
			}
			else {
				long k=-1;
				if(aa<0) {
					k=aa/bb;
					if(aa%bb!=0) {
						--k;
					}
				}
				else if(aa==0) {
					k=0;
				}
				else {
					k=aa/bb;
				}
				if(A[i-1]<=k) {
					result+=Math.min(k,A[i]-1)-A[i-1]+1;
				}
			}

		}
		return result;
	}
}

problem3 link

从小到大依次枚举每个币种的面值。假设要求的答案为$f(n,K)$。当枚举第二种面值的时候,假设是2,那么后面所有的面值都是2的倍数,所以此时$f(n,K)=n$%$2+f(\frac{n}{2},K-1)$。

import java.util.*;
import java.math.*;
import static java.lang.Math.*;

public class NewMoneySystem {
	
	public long chooseBanknotes(String N,int K) {
		map=new HashMap<>();
		return dfs(Long.valueOf(N),K);
	}

	static Map<Long,Map<Integer,Long>> map=null;

	long dfs(long n,int k) {
		if(k==1) {
			return n;
		}
		if(n==0) {
			return 0;
		}
		Map<Integer,Long> t=map.get(n);
		if(t==null) {
			t=new HashMap<>();
			map.put(n,t);
		}
		if(t.get(k)!=null) {
			return t.get(k);
		}
		long result=-1;
		for(int i=2;i<=5;++i) {
			long tmp=n%i+dfs(n/i,k-1);
			if(result==-1||result>tmp) {
				result=tmp;
			}
		}
		t.put(k,result);
		return result;
	}

}