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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

简单环题解

發布時間:2023/12/3 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简单环题解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡單環

題解:

題目求環的情況
如果我們直接枚舉會有很多重復,為了避免重復,我們枚舉起點,其他的點的序號都必須比起點大,也就是x->y,x一定小于y
dp[i][j]表示的是以i的第一個點作為起點的鏈的數量,j是終點
i是二進制,表示選擇了哪些點
我們先當作鏈來考慮
我們從點j到點t,

狀態轉移: dp[i|(1<<(t-1))][t]=(dp[i|(1<<(t-1))][t]+dp[i][j])%mo;

前置條件為:i的第t-1位為0,i的第j-1位上為1(也可以是dp[i][j]不為0),j到t有邊
現在我們就構造了一個鏈,中間為t,鏈上的點為i中為1的部分,現在如何考慮環?我們將鏈首位相接即為環,也就是我們找到i的二進制下從低到高出現1的第一個位置z,然后與t相連,當然z和t必須可連才行
統計答案時要除以2,因為每個環都統計了順時針和逆時針兩種情況
詳細看代碼

代碼:

#include<iostream> #include<stack> #include<set> #include<cstring> #include<cmath> #include<stdlib.h> #include<cstdio> #include<queue> #include<algorithm> #include<string> #include<vector> #include <queue> #include <bitset> #include <limits.h> using namespace std; typedef long long ll; const ll mo=998244353; int dp[(1<<20)+100][21]; int e[21][21]={0}; ll kk[50]; ll kpow(ll a,ll b) {ll ans=1;while(b){if(b&1) ans=(ans*a)%mo;a=(a*a)%mo;b>>=1LL;}return ans; } inline int ffs(int x) {for(int i=0;i<30;i++){if(x&(1<<i)) return i+1;}return 0; } inline int popcount(int x) { int num=0;for(int i=0;i<=20;i++){if(x&(1<<i)) num++;}return num; } int main() {ll inv2=kpow(2LL,mo-2);int n,m,k;scanf("%d%d%d",&n,&m,&k);int x,y;for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);e[x][y]=1;e[y][x]=1;}for(int j=1;j<=n;j++){dp[0|(1<<(j-1))][j]=1;}for(int i=1;i<=(1<<n)-1;i++){int x=ffs(i);//從低到高出現1的第一個位置 for(int j=1;j<=n;j++) if(dp[i][j]){for( int t=x+1;t<=n;t++){ if((i&(1<<(t-1)))||e[j][t]==0) continue;dp[i|(1<<(t-1))][t]=(dp[i|(1<<(t-1))][t]+dp[i][j])%mo;}int y=__builtin_popcount(i);//計算里面有多少個1 if(e[j][x]&&y>2) kk[y%k]=(kk[y%k]+dp[i][j])%mo;}}for(int i=0;i<k;i++)kk[i]=kk[i]*inv2%mo;for(int i=0;i<k;i++)printf("%lld\n",kk[i]);return 0; }

總結

以上是生活随笔為你收集整理的简单环题解的全部內容,希望文章能夠幫你解決所遇到的問題。

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