AOJ 2015 リズムマシーン

問題概要

N個のリズムパターンが与えられたとき、それをまとめたリズムパターンを出力せよ。
答えが2048文字以下にならない場合"Too complex."を出力せよ。


リズムパターンは16進数の2桁がm組並んできたものである。
i番目のリズムは1小節のi/mのタイミングで演奏される。
また、16進数が表すのは音で、j番目のビットがonであることは、jの高さの音が鳴っていることを意味する。


N≦8であり、それぞれのリズムパターンの文字数は2048を超えない。
また、入力のリズムパターンにおいて、各パターンのonであるビットの数は高々1つであり、同じタイミングで同じ音が複数個鳴ることはないと仮定してよい。

解法

各パターンの長さの最小公倍数が答えのパターンの長さである。
また、同一リズムを演奏するパターンには最も短いものがある

例
10002000は
1020と同一である

ため、各パターンに約分のような操作をあらかじめ施す必要がある。
(というかその部分がコードの大部分)

ソースコード

int n;
int rythm[8][1024],len[8];

int toi(char c)
{
	if(isdigit(c))return c-'0';
	return c-'A'+10;
}
char toa(int a)
{
	if(a<10)return '0'+a;
	return 'A'+a-10;
}
int minimize(int *r,int l)
{
	int mxi=1;
	for(int i=2;i<=l;i++)if(l%i==0)
	{
		bool fail=0;
		rep(j,l)if(j%i&&r[j]){fail=1;break;}
		
		if(!fail)mxi=i;
	}
	rep(i,l/mxi)r[i]=r[i*mxi];
	return l/mxi;
}

int main()
{
	int cs; cin>>cs;
	while(cs--)
	{
		cin>>n;
		rep(i,n)
		{
			char c[2100]; cin>>c;
			for(int j=0;c[j];j+=2)rythm[i][j/2]=toi(c[j])*16+toi(c[j+1]);
			len[i]=minimize(rythm[i],strlen(c)/2);
		}
		int ans[1024]={0},anslen=1;
		rep(i,n)
		{
			int g=__gcd(anslen,len[i]);
			anslen*=len[i]/g;
			if(anslen>1024)
			{
				cout<<"Too complex."<<endl; goto END;
			}
		}
		rep(i,n)rep(j,len[i])ans[j*anslen/len[i]]|=rythm[i][j];
		rep(i,anslen)cout<<toa(ans[i]/16)<<toa(ans[i]%16);
		cout<<endl;
		
		END:;
	}
	return 0;
}