\(O(n^3)\)跑跑跑,至关与\(LCS\)加一维,而后考场上彷佛内存炸了,突发奇想改了\(short\)A掉了,妙啊ios
考虑只枚举\(2-3\)这样的边,而后对答案的贡献就是,(u所链接点的个数-1) * (v所链接点的个数-1)而后再减去一个重复计算的部分,就是同时链接了\(u\)和\(v\)的点作的贡献
像这样
5显然作了两次贡献
\((d_u - 1) * (d_v - 1) - son[u]\cap son[v]\)
获得了70分的好成绩
而后用\(bitset\)维护一下取交集的操做就okk了
注意题目中较小的数据范围spa
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <bitset> using namespace std; inline int read(){ int x = 0, w = 1; char ch = getchar(); for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; return x * w; } const int ss = 2333; bitset<1501> b[ss]; int d[ss]; long long dp[ss][ss], ans; char s[ss][ss]; signed main(){ freopen("tourist.in", "r", stdin); freopen("tourist.out", "w", stdout); int n = read(); for(register int i = 1; i <= n; i++) scanf("%s", s[i] + 1); for(register int i = 1; i <= n; i++) dp[1][i] = 1; for(register int i = 1; i <= n; i++) for(register int j = 1; j <= n; j++) if(s[i][j] == '1') d[i]++; for(register int t = 2; t <= 4; t++) for(register int i = 1; i <= n; i++) for(register int j = 1; j <= n; j++) if(s[i][j] == '1') dp[t][i] += dp[t - 1][j]; for(register int i = 1; i <= n; i++) ans += dp[4][i]; for(register int i = 1; i <= n; i++) ans -= d[i] * d[i] * 2; for(register int i = 1; i <= n; i++){ for(register int j = 1; j <= n; j++){ if(s[i][j] == '1') b[i][j] = 1, ans++; } } for(register int i = 1; i <= n; i++){ for(register int j = i + 1; j <= n; j++){ if(b[i][j]) ans -= (b[i] & b[j]).count() * 2; } } cout << ans << endl; }
对于每个值,只有可能和本身的子集连边,而后不得不复习一下如何求一个数的全部子集code
signed main(){ int n = read(); for(register int i = n; i; i = (i - 1) & n) cout << i << endl; }