Particle

競技プログラミングについての雑記

SRM 659 Div1 Medium CampLunch

想定解とはおそらく少し違う方法で解いた (定数倍高速化を頑張って TLE ギリギリなので、想定解が思いつくならそちらの方がよい。)

まず、i 日目で隣り合う 2 人がどうペアになるか全列挙し、高速ゼータ変換を行う。すると、i 日目の食事で、ペアにできない人の集合を固定したときに、何通りあるかが計算できる。
各人の状態を「前の日と2連続」、「次の日と2連続」、「どちらでもない」の 3 通りにして DP をすると、計算量が O(N*3^M)になる。(DP テーブルとして持つのは、「前の日と2連続」、「それ以外」の 2 通り)
定数倍高速化することで 1.95 sec くらいになる。(ローカルでは、サンプルが、3.6 sec)

#define L 16
ll dp[L+1][1<<L];
ll dp2[1<<L];
vector<string> a;

class CampLunch {
	public:
	int f(int i, int j){
		return a[i][j]-'A';
	}
	int count(int n, int m, vector <string> a_) {
		a=a_;
		mset(dp, 0);
		ll mask = (1<<m)-1;
		dp[0][0] = 1;
		rep(i, n){
			mset(dp2, 0);
			rep(j, 1<<(m-1)){
				int j2 = j;
				bool ok = true;
				while(j2){
					if((j2&3)==3) ok = false;
					j2 >>= 1;
				}
				if(!ok) continue;
				int t = 0;
				rep(k, m-1){
					if(1&(j>>k)){
						t |= 1<<f(i, k);
						t |= 1<<f(i, k+1);
					}
				}
				dp2[t^mask]++;
			}
			rep(j, m) rep(b, 1<<m) if(0==(1&(b>>j))) dp2[b] += dp2[b|(1<<j)];
			rep(j, 1<<m){
				for(int k = j; ;k=(k-1)&j){
					(dp[i+1][k]+=dp[i][j&~k]*dp2[j]);
					if(k==0) break;
				}
			}
			rep(j, 1<<m) dp[i+1][j]%=mod;
		}
		return dp[n][0];
	}
};