日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CF1408G:Clusterization Counting(区间dp、克鲁斯卡尔重构树)

發布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CF1408G:Clusterization Counting(区间dp、克鲁斯卡尔重构树) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

解析

很妙的一道題
看這兩個南轅北轍的標簽就知道這題不簡單
看見dp思路還是得打開
一開始其實想到按邊權排序了
但卡在了重構樹上
遇到dp一定要敢想
勇于和圖論等結合

考慮正解
按照邊權升序排序
依次加邊到圖中
并查集維護連通性和集合內的邊數
發現,一個聯通塊合法當且僅當它在某個時刻是當前圖的一個
(這個概念還是現查的…)

考慮建一個重構樹
顯然所以合法的區間在樹上對應的葉子的dfs序是連續的
可以通過dfs求出合法的區間,并記錄哪些區間可以進行轉移
最后進行一遍樸素dp即可
由于合法的區間只會有On個,所以均攤復雜度是n2n^2n2

代碼

#include<bits/stdc++.h> using namespace std; const int N=1550; const int mod=998244353; #define ll long long ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();};while(isdigit(c)){x=x*10+c-'0';c=getchar();};return x*f; }int n,m; struct node{int to,nxt; }p[N<<1]; int fi[N<<1],cnt; inline void addline(int x,int y){p[++cnt]=(node){y,fi[x]};fi[x]=cnt;return; }struct edge{int x,y,w; }e[N*N]; bool cmp(edge a,edge b){return a.w<b.w; } int fa[N<<1],siz[N<<1],num[N<<1],tot,id,ls[N<<1],rs[N<<1],tim; bool jd[N][N]; int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} void dfs(int x){if(fi[x]==-1){siz[x]=1;ls[x]=rs[x]=++tim;jd[tim][tim]=1;return;}for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;dfs(to);siz[x]+=siz[to];if(!ls[x]) ls[x]=ls[to];else rs[x]=rs[to];}int o=rs[x]-ls[x]+1;jd[ls[x]][rs[x]]=num[x]==o*(o-1)/2;//printf("x=%d ls=%d rs=%d num=%d\n",x,ls[x],rs[x],num[x]);return; } ll dp[N][N]; int main(){#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();id=n;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){int x=read();if(i<j) e[++tot]=(edge){i,j,x};}}for(int i=1;i<=n*2;i++) fa[i]=i;sort(e+1,e+1+tot,cmp);for(int i=1;i<=tot;i++){int x=e[i].x,y=e[i].y;x=find(x),y=find(y);if(x==y){num[x]++;continue;}++id;fa[x]=fa[y]=id;num[id]=num[x]+num[y]+1;addline(id,x);addline(id,y);}dfs(id);dp[0][0]=1;for(int i=1;i<=n;i++){for(int k=1;k<=i;k++){if(!jd[k][i]) continue;for(int j=1;j<=n;j++){(dp[i][j]+=dp[k-1][j-1])%=mod;}}}for(int i=1;i<=n;i++) printf("%lld ",dp[n][i]);return 0; } /**/ 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的CF1408G:Clusterization Counting(区间dp、克鲁斯卡尔重构树)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。