題意:
sol :前排膜拜
雖然dalao們說了一些最小表示法啊什麼k=5時只有52種狀態啊balabala,然而我並不會.......
因為k很小,可以考慮用狀壓來記錄聯通塊資訊,考慮dp
dp[i][j]表示前i個點,最後k個點聯通情況為j時的方案數
由於n很大,考慮採用矩陣快速冪優化,用並查集判環&維護
那麼最終可以建構函式f[x][y]表示狀態x向狀態y轉移有多少種合法的連線方式
初始函式g[x]是乙個行向量,每個位置代表乙個初始狀態
這樣就可以做了........最後輸出a[1][1]即可
#include#include#include
#include
#define ll long long
using
namespace
std;
const
int mx=200
;const
int p=65521
;using
namespace
std;
ll n;
int k,tot/*
狀態總數
*/,tr_siz=/*
完全圖的生成樹個數*/;
int fa[mx],siz[mx]/*
第i個聯通塊的大小
*/,status[600],hash[1
<<16]/*
hash[s]=狀態s的編號*/;
struct
matrix
}a,trans;
matrix
operator*(matrix a,matrix b)
void
pow(ll c)
}void dfs(int x,int sta) //
當前要加入第x個點的聯通狀態,當前的狀態為sta
int tmp=-1; //
聯通塊的最大編號,聯通塊編號的區間是[0,k-1]
for(int i=1;i//
!!!當前的sta裡只儲存了1~pos-1這些點的連通性
tmp=max(tmp,sta>>((i-1)*3)&7
);
for(int i=0;i<=tmp+1&&i)
dfs(x+1,sta<<3|i);
}int find(int
x) int get_status() //
用當前的並查集來求出新的點2到點k+1的最小表示
return
hash[sta];
}void cal(int sta,int addsta) //
用加邊狀態addsta去更新最小表示法sta,addsta裡的第i位為1表示第k+1個點要和點i+1連新邊
for(int i=1;i<=k;i++)
if(addsta&(1
<<(i-1
)))
bool flag=false; //
flag=true表示有點和點1聯通
for(int i=2;i<=k+1;i++)
if(find(i)==find(1
))
if(!flag) return; //
點1不鏈結後面的點,那麼這個生成樹不聯通
trans.num[sta][get_status()]++;
}int
main()
BZOJ 1491 NOI2007 社交網路
顯然這是一道要求多源最短路的題目,資料範圍很小,目測用弗洛伊德演算法。由題意,先求出各個點之間的最短路徑,同時利用乘法原理,計算出由 i 到 j 之間的最短路徑個數。如果又發現了一條最短路,由乘法原理計算增加的路徑個數再加上即可。我寫的 沒有去除自己到自己的路徑,因此需清空,但也可在 floyd 中...
BZOJ 1491 NOI2007 社交網路
傳送門 資料範圍很小,我們考慮floyd。要求的是路徑條數,所以我們在floyd的時候直接預處理出兩點之間的路徑條數。用num i j 表示,然後floyd的時候,如果dis i j include include include using namespace std const int maxn...
BZOJ 1491 NOI2007 社交網路
鏈結 我是鏈結,點我呀 題意 在這裡輸入題意 題解 floyd演算法 算出任意兩點之間的最短路,以及最短路的條數。然後三重迴圈列舉v,s,t就好 看看s到t的最短路徑不經過v 經過的話增加答案貢獻 o n 3 include include define ll long long using nam...