881012367360
比赛的时候傻了居然用暴搜,感觉复杂度差不多没想到位运算快这么多,还好是省赛是国赛的话肯定与一等奖无缘了。
思考了下为什么是对的,从000…1->111…1每个状态计算时它的子集都更新完了不会再更新,所以是对的。
差不多最坏2^21 * 21 * 21 = 924,844,032
次运算(其实还可以剪),暴搜的话最坏要21!=51,090,942,171,709,440,000
就炸了。
#include <iostream>
#include <cstring>
#include <algorithm>
typedef long long LL;
using namespace std;
const int N = 21, INF = 0x3f3f3f3f;
int g[N][N], n;
LL dp[1 << N][N];
int gcd(int a, int b){
return b ? gcd(b, a % b) : a;
}
int main(){
n = 21;
for(int i = 0; i < n; i ++ )
for(int j = 0; j < n; j ++ )
{
if(gcd(i + 1, j + 1) == 1) g[i][j] = g[j][i] = 1;
}
dp[1][0] = 1;
for(int i = 0; i < 1 << n ; i ++ ){
for(int j = 0; j < n; j ++ ){
if(i >> j & 1){
for(int k = 0; k < n; k ++ ){
int last_state = i ^ (1 << j);
if(last_state >> k & 1){
// dp[i][j] = min(dp[i][j], dp[last_state][k] + g[k][j]);
if(g[k][j])
dp[i][j] += dp[last_state][k];
}
}
}
}
}
LL res = 0;
for(int i = 1; i < n; i ++ )
res += dp[(1 << n) - 1][i];
cout << res;
return 0;
}