AOJ2105 Rhythm Machine

問題リンク Rhythm Machine

  • 解法

N個それぞれのリズムの最短表現を作った後、それらを合わせた最短表現を作る、というステップで解けます。
各リズムの最短表現は最大公約数を使って作ることができます。[和音の個数]と[音が鳴る小節k]全てのGCDをとります(0小節目でなったときは無視します)。求まったGCDで和音の個数とkを全て割れば最短表現になります。サンプル3を例に挙げると、和音の個数が8、音が鳴る小節はそれぞれ0, 2, 4, 6なのでこれらのGCDは2です。よって、2で割って、和音の個数4、なる小節は0, 1, 2, 3という最短表現が完成します。
次にこの結果を合わせた最短表現の作り方です。まず、必要になる和音の個数は、各和音の個数の最小公倍数だけ必要になります。なお、この最小公倍数LCMが1024を超えたら、結果の文字列が2048を超えるので"Too complex."となります。後は、各リズムについて、分母をLCMにそろえて各小節について、和音を合わせるだけです。16進数表現を得るために
String.format("%02X", waon);
とするのが楽だと思います。

  • ソース
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

//Rhythm Machine
public class AOJ2105 {

	class R implements Comparable<R>{
		int k, c;
		public R(int k, int c) {
			this.k = k;
			this.c = c;
		}
		public int compareTo(R o) {
			return k-o.k;
		}
	}
	
	int gcd(int a, int b){
		return b==0?a:gcd(b, a%b);
	}
	int lcm(int a, int b){
		int g = gcd(a, b);
		return a/g*b;
	}
	
	@SuppressWarnings("unchecked")
	void run(){
		Scanner sc = new Scanner(System.in);
		int T = sc.nextInt();
		while(T--!=0){
			int n = sc.nextInt();
			int[] N = new int[n];
			List<R>[] l = new List[n];
			for(int i=0;i<n;i++){
				l[i] = new ArrayList<R>();
				char[] s = sc.next().toCharArray();
				N[i] = s.length/2;
				int g = N[i];
				for(int k=0;k<N[i];k++){
					int c = (s[k*2]-'0')*16+s[k*2+1]-'0';
					if(c==0)continue;
					l[i].add(new R(k, c));
					if(k!=0)g = gcd(g, k);
				}
				if(l[i].isEmpty())continue;
				N[i]/=g;
				for(R r:l[i])r.k/=g;
			}
			int lcm = 1;
			for(int i=0;i<n;i++){
				if(1024<lcm||l[i].isEmpty())continue;
				lcm = lcm(lcm, N[i]);
			}
			if(1024<lcm){
				System.out.println("Too complex."); continue;
			}
			List<R> res = new ArrayList<R>();
			for(int i=0;i<n;i++){
				int mul = lcm/N[i];
				for(R r:l[i])res.add(new R(r.k*mul, r.c));
			}
			if(res.isEmpty())System.out.println("00");
			else{
				Collections.sort(res);
				int[] a = new int[lcm];
				for(R r:res)a[r.k]+=r.c;
				StringBuilder sb = new StringBuilder();
				for(int i=0;i<lcm;i++)sb.append(String.format("%02X", a[i]));
				System.out.println(sb);
			}
		}
	}
	
	public static void main(String[] args) {
		new AOJ2105().run();
	}
}