时间:3000ms左右的代码(并查集维护,邻接矩阵暴力跑重建的边)
update:把并查集处理后跑祖先间的边,换为重建图,效率或许可以提高.(已确认,可以优化到850ms左右,代码附在后面)
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <bitset>
#define maxn 3002
#define maxm 8000020
using namespace std;
inline void read(int &x) {
char ch;
bool flag = false;
for (ch = getchar(); !isdigit(ch); ch = getchar())if (ch == '-') flag = true;
for (x = 0; isdigit(ch); x = x * 10 + ch - '0', ch = getchar());
x = flag ? -x : x;
}
inline void write(int x) {
static const int maxlen = 100;
static char s[maxlen];
if (x < 0) { putchar('-'); x = -x;}
if (!x) { putchar('0'); return; }
int len = 0; for (; x; x /= 10) s[len++] = x % 10 + '0';
for (int i = len - 1; i >= 0; --i) putchar(s[i]);
}
int n;
int pre[maxm],now[maxn],son[maxm],tot;
int dfn[maxn],low[maxn],cnt;
int fa[maxn];
int d[maxn],top;
bool IN[maxn];
int size[maxn];
bitset<maxn> g[maxn];
int sum[maxn];
void build(int a,int b){
pre[++tot]=now[a];
now[a]=tot;
son[tot]=b;
}
int get(int x){
if (x!=fa[x])
return fa[x]=get(fa[x]);
return x;
}
void dfs(int x){
dfn[x]=low[x]=++cnt; d[++top]=x;
IN[x]=1;
for (int p=now[x];p;p=pre[p])
if (dfn[ son[p] ]==0)
{
dfs(son[p]);
low[x]=min(low[x],low[son[p]]);
}
else
if (IN[son[p]])
low[x]=min(low[x],dfn[son[p]]);
if (low[x]==dfn[x])
{
while ( d[top]!= x )
{
fa[ get ( d[top] ) ] =get(x);
IN[ d[top] ]=0;
--top;
}
--top;
IN[x]=0;
}
}
char s[maxn];
bool bo[maxn][maxn];
bool vis[maxn];
void doit(int x){
for (int i=1;i<=n;i++)
if (fa[i]==i)
if (g[x][i])
if(!vis[i])
{
doit(i);
g[x]|=g[i];
}
else
g[x]|=g[i];
vis[x]=1;
}
int main(){
read(n);
for (int i=1;i<=n;i++)
{
scanf("%s",s);
int len=strlen(s);
for (int j=0;j<len;j++)
if (s[j]=='1')
build(i,j+1);
}
for (int i=1;i<=n;i++)
fa[i]=i;
for (int i=1;i<=n;i++)
if (dfn[i]==0)
dfs(i);
for (int i=1;i<=n;i++)
for (int p=now[i];p;p=pre[p])
if (get(son[p])!=get(i))
g[get(i)][get( son[p] )]=1;
for (int i=1;i<=n;i++)
if (fa[i]==i)
doit(i);
for (int i=1;i<=n;i++)
size[ get(i) ]++;
int ans=0;
for (int i=1;i<=n;i++)
if (fa[i]==i)
{
int sum=size[i];
for (int j=1;j<=n;j++)
if (fa[j]==j)
if (g[i][j])
sum+=size[j];
ans+=sum*size[i];
}
printf("%d\n",ans);
return 0;
}
时间:850ms左右 (染色后重建图,降低点和边的数量)
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bitset>
#define maxn 3002
#define maxm 4000020
using namespace std;
inline void read(int &x) {
char ch;
bool flag = false;
for (ch = getchar(); !isdigit(ch); ch = getchar())if (ch == '-') flag = true;
for (x = 0; isdigit(ch); x = x * 10 + ch - '0', ch = getchar());
x = flag ? -x : x;
}
inline void write(int x) {
static const int maxlen = 100;
static char s[maxlen];
if (x < 0) { putchar('-'); x = -x;}
if (!x) { putchar('0'); return; }
int len = 0; for (; x; x /= 10) s[len++] = x % 10 + '0';
for (int i = len - 1; i >= 0; --i) putchar(s[i]);
}
int n;
int pre[maxm],now[maxn],son[maxm],tot;
int _pre[maxm],_now[maxn],_son[maxm],_tot;
int dfn[maxn],low[maxn],cnt;
int d[maxn],top;
bool IN[maxn];
int size[maxn],color[maxn],color_tot;
bitset<maxn> g[maxn];
void build(int a,int b){
pre[++tot]=now[a];
now[a]=tot;
son[tot]=b;
}
void _build(int a,int b){
_pre[++_tot]=_now[a];
_now[a]=_tot;
_son[_tot]=b;
}
void dfs(int x){
dfn[x]=low[x]=++cnt; d[++top]=x;
IN[x]=1;
for (int p=now[x];p;p=pre[p])
if (dfn[ son[p] ]==0)
{
dfs(son[p]);
low[x]=min(low[x],low[son[p]]);
}
else
if (IN[son[p]])
low[x]=min(low[x],dfn[son[p]]);
if (low[x]==dfn[x])
{
++color_tot;
while ( d[top]!= x )
{
color[ d[top] ]=color_tot;
IN[ d[top] ]=0;
--top;
}
--top;
IN[x]=0;
color[x]=color_tot;
}
}
void rebuild(){
for (int i=1;i<=n;i++)
for (int p=now[i];p;p=pre[p])
if ( color[ son[p] ] !=color[ i ] )
if (!g[ color[i] ] [ color[son[p]] ])
{
g[ color[i] ] [ color[son[p]] ] = 1;
_build(color[i],color[son[p] ]);
}
}
char s[maxn];
bool bo[maxn][maxn];
bool vis[maxn];
void doit(int x){
for (int p= _now[x] ;p;p= _pre [p])
if (!vis[ _son[p] ])
{
doit( _son[p] );
g[x]|=g[ _son[p] ];
}
else
g[x]|=g[ _son[p] ];
vis[x]=1;
}
int main(){
read(n);
for (int i=1;i<=n;i++)
{
scanf("%s",s);
int len=strlen(s);
for (int j=0;j<len;j++)
if (s[j]=='1')
build(i,j+1);
}
for (int i=1;i<=n;i++)
if (dfn[i]==0)
dfs(i);
for (int i=1;i<=n;i++)
size[ color[i] ]++;
rebuild();
for (int i=1;i<=color_tot;i++)
if (!vis[i])
doit(i);
int ans=0;
for (int i=1;i<=color_tot;i++)
{
int sum=size[i];
for (int j=1;j<=color_tot;j++)
if (g[i][j])
sum+=size[j];
ans+=sum*size[i];
}
printf("%d\n",ans);
return 0;
}