kmjp's blog

競技プログラミング参加記です

SoundHound Programming Contest 2018 Masters Tournament 本戦 : C - Not Too Close

オンサイトにしてはマイルドな難易度?
https://beta.atcoder.jp/contests/soundhound2018-summer-final-open/tasks/soundhound2018_summer_final_c

問題

正整数N,Dに対し、以下を満たす無向グラフの組み合わせを求めよ。

  • N頂点の無向グラフで、自己辺・多重辺をもたない。
  • 各頂点は1~Nの番号を持つ。
  • 1番から2番の頂点の最短距離はDである。

解法

以下の値を考える。
f(d, left, pre) := 1番の頂点から距離d以下の頂点までの配置を決めたとき、残り未配置の頂点がleft個であり、距離dの頂点がpre個である。

1番と2番の頂点を除いた(N-2)個の頂点の並び順を決めるので、f(0,N-2,1)から順に上記値を埋めていこう。
距離dの頂点のうち1個以上とつながる頂点は距離d+1となるので、距離d+1の点がx個ある場合を考えて以下の和を取っていく。
f(d+1, left-x, x) += f(d, left, pre) * comb(left, x) * (2^comb(x,2)) * *1^left)*(2^comb(left,2))が加算される。

(2^pre-1)は、2番の頂点は距離(D-1)にあるpre個のいずれかの頂点と接続する必要があることを意味する。
*2^left)は、残りleft個の頂点は距離(D-1)にあるpre個および2番の頂点計(pre+1)個の頂点の間の辺の有無の組み合わせを意味する。
最後の(2^comb(left,2))は、left個の点同士の間は辺があってもなくてもよいことを示す。

int N,D;
ll mo=1000000007;
ll dp[31][31][31];
const int CN=41;
ll C[CN][CN];
ll p2[1010];


ll modpow(ll a, ll n = mo-2) {
	ll r=1;a%=mo;
	while(n) r=r*((n%2)?a:1)%mo,a=a*a%mo,n>>=1;
	return r;
}

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	FOR(i,CN) for(j=0;j<=i;j++) C[i][j]=(j==0||j==i)?1:(C[i-1][j-1]+C[i-1][j])%mo;
	p2[0]=1;
	FOR(i,1000) p2[i+1]=p2[i]*2%mo;
	
	cin>>N>>D;
	dp[1][N-2][1]=1;
	for(i=2;i<=D;i++) {
		for(int left=1;left<=N-2;left++) {
			for(int pre=1;pre<=N-2;pre++) if(dp[i-1][left][pre]) {
				for(x=1;x<=left;x++) (dp[i][left-x][x]+=dp[i-1][left][pre]*C[left][x]%mo*p2[x*(x-1)/2]%mo*modpow(p2[pre]+mo-1,x))%=mo;
			}
		}
	}
	ll ret=0;
	for(int left=0;left<=N-1;left++) {
		for(x=1;x<=N-1;x++) if(dp[D][left][x]) {
			(ret+=dp[D][left][x]*(p2[x]+mo-1)%mo*modpow(p2[x+1],left)%mo*p2[left*(left-1)/2])%=mo;
		}
	}
	cout<<ret<<endl;
	
}

まとめ

最初木・森縛りがあると勘違いして、「これO(N^3)で行けるのになんでNの上限が小さいんだ?」と思ってしまった。

*1:2^pre-1)^x) 1つめのcombは、距離(d+1)に配置する点をleft個からx個選ぶことに相当する。 2^comb(x,2)の部分は、距離(d+1)の点同士の間は辺があってもなくてもよいことを示す。 ((2^pre-1)^x)の部分は、距離(d+1)のx個の頂点は、距離dにあるpre個の頂点の1個以上とつながる必要があることを示す。 こうしてf(D-1,left,pre)を求めたら、残された2番の頂点およびleft個の頂点の配置を決めよう。 答えにはf(D-1,left,pre)*(2^pre-1)*((2^(pre+1

*2:2^(pre+1