結果
| 問題 |
No.352 カード並べ
|
| コンテスト | |
| ユーザー |
startcpp
|
| 提出日時 | 2016-03-12 00:20:11 |
| 言語 | C++11(廃止可能性あり) (gcc 13.3.0) |
| 結果 |
RE
|
| 実行時間 | - |
| コード長 | 1,496 bytes |
| コンパイル時間 | 443 ms |
| コンパイル使用メモリ | 55,988 KB |
| 実行使用メモリ | 83,236 KB |
| 最終ジャッジ日時 | 2024-09-25 01:42:37 |
| 合計ジャッジ時間 | 10,395 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | RE * 1 TLE * 2 |
| other | -- * 6 |
ソースコード
//だめだ
//数字を1,2,3…とみていくのではなく、挿入箇所を左から順に見ていく。それで、どの数字を入れるかを全探索する。
//すると、(最も右のカード(N通り), 未使用のカード組(2^N通り))から「次の操作でかかるコスト」を計算できる。
//そして、操作後の(最も右のカード(N通り), 未使用のカード組(2^N通り))もそれ自身から計算できる。
//コスト和は、「操作でかかるコスト + これからのコスト」を計算すれば求まる。期待値は適当に平均とるだけ。
//…O(N * 2^N)のDPを組める気がしてきた!!
#include <iostream>
#include <cstdio>
using namespace std;
int n;
double dp[21][1<<21];
//簡単化のため、depも引数にするが、これが無くてもDPできる。
double dfs(int prev, int remain, int dep){
if( dep == n ){ return 0; }
//if( dp[prev][remain] >= 0 ){ return dp[prev][remain]; }
double ret = 0;
for( int i = 1; i <= n; i++ ){
if((remain >> i) & 1){ //数字iが未使用
remain &= ~(1 << i);
int cst = (dep == 0 || dep == n-1) ? 1 : prev * i;
ret += cst + dfs(i, remain, dep + 1);
remain |= (1 << i);
}
}
ret /= n - dep; //未使用の個数で割る
return (dp[prev][remain] = ret);
}
int main(){
cin >> n;
for( int i = 0; i <= n; i++ )
for( int j = 0; j < 1<<(n+1); j++ )
dp[i][j] = -1;
int remain = (1<<(n+1)) - 2;
printf("%.14f\n", dfs(-1, remain, 0));
return 0;
}
startcpp