topcoder srm 390 div1

problem1 link

记录一个模$k$之后的值是否出现过,出现过则出现循环,无解;否则最多$k$ 次一定能出现0.

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

public class ConcatenateNumber {
	
	public int getSmallest(int number, int k) {
		if(k==1) {
			return 1;
		}
		boolean[] f=new boolean[k];
		final long b=getbase(number);
		int cur=0;
		for(int i=1;;++i) {
			cur=(int)((cur*b+number)%k);
			if(cur==0) {
				return i;
			}
			if(f[cur]) {
				return -1;
			}
			f[cur]=true;
		}
	}

	long getbase(int x) {
		long result=1;
		while(x>0) {
			result*=10;
			x/=10;
		}
		return result;
	}
}

  

problem2 link

最朴素的方法应该是令$f[i][mask]$表示处理前$i$块板子使用的painter的集合是$mask$的最小值,但是这样会超时。

时间上可以接受的方法是二分。首先列举所有可能的时间,然后对时间进行二分。二分之后,令$p[i][j]$表示第$i$个painter从第$j$个board开始能涂到的板子的编号。然后进行动态规划。令$dp[mask]$表示$mask$集合的painter可以涂到的板子的最大编号。

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

public class PaintingBoards {



	public double minimalTime(int[] boardLength, int[] painterSpeed) {
		final int n=boardLength.length;
		final int m=painterSpeed.length;
		List<Double> list=new ArrayList<>();
		for(int i=0;i<n;++i) {
			double cur=0;
			for(int j=i;j<n;++j) {
				cur+=boardLength[j];
				for(int k=0;k<m;++k) {
					list.add(cur/painterSpeed[k]);
				}
			}
		}
		Collections.sort(list);
		int low=0,high=list.size()-1;
		int result=high;
		while(low<=high) {
			int mid=(low+high)>>1;
			if(check(list.get(mid),boardLength,painterSpeed)) {
				result=Math.min(result,mid);
				high=mid-1;
			}
			else {
				low=mid+1;
			}
		}
		return list.get(result);
	}

	boolean check(double mid,int[] board,int[] painter) {
		final int n=board.length;
		final int m=painter.length;
		int[][] p=new int[m][n];
		for(int i=0;i<m;++i) {
			final double s=mid*painter[i]+1e-10;
			for(int j=0;j<n;++j){
				double x=0;
				int y=j;
				while(y<n&&x+board[y]<=s) {
					x+=board[y++];
				}
				p[i][j]=y;
			}
		}
		int[] f=new int[1<<m];
		for(int i=1;i<(1<<m);++i) {
			for(int j=0;j<m;++j) {
				if((i&(1<<j))!=0) {
					if(f[i^(1<<j)]==n) {
						f[i]=n;
						break;
					}
					f[i]=Math.max(f[i],p[j][f[i^(1<<j)]]);
				}
			}
		}
		return f[(1<<m)-1]==n;
	}

}

  

problem3 link

分两步:

第一步,计算使用$i$个可以拼成的集合$all[i]$,$1 leq i leq 10$;

第二步,从$frac{a}{b}$开始进行逆向搜索,令集合$unall[i]$中的每个元素$x$表示$x$可以和某个$all[i]$中的元素$y$可以组装成$frac{a}{b}$。

import com.sun.imageio.spi.RAFImageInputStreamSpi;

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

public class BuildCircuit {


	static long gcd(long x,long y) {
		return y==0?x:gcd(y,x%y);
	}

	static class Rational {
		public long p;
		public long q;

		public Rational() {}
		public Rational(long x,long y) {
			long t=gcd(x,y);
			this.p=x/t;
			this.q=y/t;
		}

		public static Rational parallel(Rational r1,Rational r2) {
			return new Rational(r1.p*r2.p, r1.p*r2.q+r1.q*r2.p);
		}

		public static Rational unparallel(Rational r1,Rational r2)
		{
			long t=r1.q*r2.p-r1.p*r2.q;
			if(t<=0) {
				return null;
			}
			return new Rational(r1.p*r2.p,t);
		}

		public static Rational serial(Rational r1,Rational r2)
		{
			return new Rational(r1.p*r2.q+r1.q*r2.p,r1.q*r2.q);
		}

		public static Rational unserial(Rational r1,Rational r2)
		{
			long t=r1.p*r2.q-r1.q*r2.p;
			if(t<=0){
				return null;
			}
			return new Rational(t,r1.q*r2.q);
		}


		public boolean equals(Object object) {
			Rational t=(Rational)object;
			return p==t.p&&q==t.q;
		}
		public int hashCode() {
			return (int)((p*1007+q)%1000000007);
		}
	}

	
	public int minimalCount(int a,int b) {
		List<List<Rational>> all=new ArrayList<>();
		for(int i=0;i<11;++i) {
			all.add(new ArrayList<>());
		}
		Rational one=new Rational(1,1);
		Rational two=new Rational(2,1);
		all.get(1).add(one);
		all.get(1).add(two);
		Map<Rational,Integer> map1=new HashMap<>();
		map1.put(one,1);
		map1.put(two,1);

		for(int i=2;i<=10;++i) {
			for(int x=1;x<=i-x;++x) {
				final int y=i-x;
				for(Rational xx:all.get(x)) {
					for(Rational yy:all.get(y)) {
						mark(map1,Rational.parallel(xx,yy),i,all.get(i));
						mark(map1,Rational.serial(xx,yy),i,all.get(i));
					}
				}
			}
		}

		List<List<Rational>> unall=new ArrayList<>();
		for(int i=0;i<11;++i) {
			unall.add(new ArrayList<>());
		}
		Rational need=new Rational(a,b);
		unall.get(0).add(need);
		Map<Rational,Integer> map2=new HashMap<>();
		map2.put(need,0);
		for(int i=1;i<=10;++i) {
			for(int x=0;x<i;++x) {
				final int y=i-x;
				for(Rational xx:unall.get(x)) {
					for(Rational yy:all.get(y)) {
						mark(map2,Rational.unparallel(xx,yy),i,unall.get(i));
						mark(map2,Rational.unserial(xx,yy),i,unall.get(i));
					}
				}
			}
		}

		int result=17;
		for(int i=0;i<=10;++i) {
			for(Rational x:unall.get(i)) {
				if(map1.containsKey(x)) {
					result=Math.min(result,i+map1.get(x));
				}
			}
		}
		if(result==17) {
			return -1;
		}
		return result;

	}

	void mark(Map<Rational,Integer> map,Rational object,int num,
			  List<Rational> list) {
		if(object==null) {
			return;
		}
		if(map.containsKey(object)) {
			return;
		}
		map.put(object,num);
		list.add(object);
	}
}

  

原文地址:https://www.cnblogs.com/jianglangcaijin/p/7537909.html