\(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; }