记录编号 146357 评测结果 AAAAAAAAAA
题目名称 [JSOI 2008] 最小生成树计数 最终得分 100
用户昵称 GravatarHouJikan 是否通过 通过
代码语言 C++ 运行时间 2.579 s
提交时间 2015-01-14 21:28:45 内存使用 7.06 MiB
显示代码纯文本
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <ctime>
#include <functional>
#define pritnf printf
#define scafn scanf
#define For(i,j,k) for(int i=(j);i<=(k);(i)++)
#define Clear(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long LL;
typedef unsigned int Uint; 
const int INF=0x3fffffff;
//==============struct declaration==============
struct adj{
  int from,to,len;
  adj(int from=0,int to=0,int len=0):from(from),to(to),len(len){}
  bool operator <(const adj &rhs) const{
    return len<rhs.len;
  }
};
//==============var declaration=================
const int MAXN=1010;
const int MOD=31011;
int n,m;
int hash[MAXN],root[MAXN],prevroot[MAXN],M[MAXN][MAXN];
int *prev,*next;
bool vis[MAXN];
adj Edge[MAXN];
//==============function declaration============
int quickpow(int a,int Exp);
int inv(int x){return quickpow(x,MOD-2);}
int findr(int x,int *R){return R[x]==x?x:R[x]=findr(R[x],R);}
int Solve_Matrix(int N);
//==============main code=======================
int main()
{  
#define FILE__
#ifdef FILE__
  freopen("bzoj_1016.in","r",stdin);
  freopen("bzoj_1016.out","w",stdout);
#endif  
  scanf("%d%d",&n,&m);
  for(int i=1;i<=m;i++)
    scanf("%d%d%d",&Edge[i].from,&Edge[i].to,&Edge[i].len);
  sort(Edge+1,Edge+1+m);
  for(int i=1;i<=n;i++) root[i]=prevroot[i]=i;
  prev=prevroot,next=root;
  long long ans=1;
  for(int x=1;x<=m;x++){
    vector <adj> G;
    for(int i=x;i<=m&&Edge[i].len==Edge[x].len;i++){
      int s=findr(Edge[i].from,prev),e=findr(Edge[i].to,prev);
      if (s==e) continue;
      G.push_back(Edge[i]);
    }
    for(int i=x;i<=m&&Edge[i].len==Edge[x].len;i++){
       x=i;
      if (findr(Edge[i].from,next)==findr(Edge[i].to,next)) continue;
      next[findr(Edge[i].from,next)]=findr(Edge[i].to,next);
    }
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++){
      if (vis[i]) continue;
      memset(hash,-1,sizeof(hash));memset(M,0,sizeof(M));
      int cnt=0;
      for(int j=0;j<G.size();j++){
        if (findr(G[j].from,next)==findr(i,next)){
          int s=findr(G[j].from,prev),e=findr(G[j].to,prev);
          if (hash[s]==-1) hash[s]=++cnt;
          if (hash[e]==-1) hash[e]=++cnt;
          M[hash[s]][hash[e]]--;M[hash[e]][hash[s]]--;
          M[hash[s]][hash[s]]++;M[hash[e]][hash[e]]++;
        }
      }
      for(int j=1;j<=n;j++)
        if (findr(i,next)==findr(j,next)) vis[j]=true;
      int temp=Solve_Matrix(cnt);
      ans=(ans*temp)%MOD;
    }  
    for(int i=1;i<=n;i++)
      prev[i]=next[i];
  }
  for(int i=1;i<=n;i++)
    if (findr(1,next)!=findr(i,next)){
      printf("0\n");
      return 0;
    }
  printf("%lld\n",ans);
  return 0;
}
//================fuction code====================
int quickpow(int a,int Exp){
  if (Exp==0) return 1;
  if (Exp==1) return 0;
  int temp=quickpow(a,Exp/2);
  temp=(temp*temp)%MOD;
  if (Exp&1) temp=(temp*a)%MOD;
  return temp;
}
int Solve_Matrix(int N){
  long long ret=1;N--;
  for(int x=1;x<=N;x++){//处理第x行 
    for(int r=x+1;r<=N;r++)
      while (M[r][x]){//类似辗转相除法将其化为0 
        int t=M[x][x]/M[r][x];
        for(int i=x;i<=N;i++)
          M[x][i]=(M[x][i]-M[r][i]*t)%MOD;
        for(int i=x;i<=N;i++)
          swap(M[x][i],M[r][i]);
        ret=-ret;//交换矩阵两行,行列式取反 
      }
    ret=(ret*M[x][x])%MOD;
  }
  return (ret+MOD)%MOD;
}