這是最終章,永久的思念。
題目大意:
有n張牌,每張牌兩面都有數字,範圍都在1到2n之間,求最少的反轉次數,使得每張牌朝上的一面的數字各不相同,並求出達到這個效果的方案數。(多測,初始時每張牌正面朝上,無解輸出「-1 -1」)
題解:20%資料(n<=20)
直接搜尋即可。
100%資料(n<=1×105)
搜尋複雜度不允許,我們試圖讓這個問題抽象化。
將牌上的數字抽象為點,牌抽象為邊,則問題轉化為:
對於一張有向圖,將某些邊翻轉,使得每個點的入度小於等於1。
先連邊,我們發現整張圖最多有2n個點,卻只有n條邊。這代表圖的連通性極差,圖被分成許多聯通塊,然後我們對於每個聯通塊進行分類討論。
設連通塊的邊數為e,點數為v。
若e若e=v,則該圖是一顆基環樹,環上的點入度不能為0,因為環上的點一定會被另乙個環上的點指向,要使條件成立,則一定是一顆基還外向樹;
若e=v+1,則該圖是一棵樹,可以先後進行兩次dfs,求出所需要的最小花費。
第一次任選一點進行dfs,由兒子向父親更新,若通過一條反邊,則在f陣列上加1,若dfs的是一顆基環樹,則還需要記錄未經過的一條邊,防止第二次dfs的路徑與第一次不同。然後進行第二次,由父親向兒子更新,若通過反邊,則在g陣列上加1,反之減1。g陣列與f陣列在搜尋樹的根處相等。
在進行第二次dfs時,將每個節點的g值壓進乙個vector裡面,然後sort一下,第乙個便是最小值,與最小值相同的數的個數便是方案數。
最後相乘即可。
單次複雜度o(nlogn)
code:
1 #include2 #include3 #include4 #include5 #include6view code#define ll long long
7using
namespace
std;
8const
int n=100010;9
const ll mod=998244353;10
int t,n,m=1,mv=0,me=0,cnt=0,tot=0,top=0
,start,endd,bridge;
11int fi[n<<1],g[n<<1],f[n<<1
];12
bool v[n<<1],vis[n<<1
];13
struct
edgee[n<<1
];16 vectorgg;
17void add(int x,int
y)18
24int
read()
2533
return
s;34}35
void
clean()
3645
void dfs(int
x)4654}
55void dfs1(int x,int
p)56
64else68}
69}70void dfs2(int x,int
p)7179}
80int
main()
8191
int flag=0;92
for(int i=1;i<=2*n;i++)
100}
101}
102if(flag==1) continue
;103
int ans1=0;ll ans2=1
;104
for(int i=1;i<=2*n;i++)
118}
119else
125 ans2=ans2*num%mod;
126}
127}
128 printf("
%d %lld\n
",ans1,ans2);
129}
130return0;
131 }
單身三連之一
乙個讓單身狗們崩潰的題 題目大意 有n件物品,一共取d次,一次取的必須少於m件,問共有多少種取法。每個物品相同,有多測,對998244353取模 題解 30 演算法 n,d 20,m 10 簡單的dp。設f i j 為取了i次,共取了j件物品的方案數,則有如下狀態轉移方程 f i j kk max ...
NOIP三連測總結
近三天舉行了三場考試,好像考得都不咋地,與上一周專題訓練相比相差甚遠。單就分數來說,基本看不下去。基本就在20名左右徘徊。但是,三天以來,從第一天思維僵化忽略各種情況到今天想到第二題正解 雖然寫掛了 個人感覺自己的狀態還是在變好,並且收穫了一些乾貨 1.對於輸入輸出接近longlong的題目,不要因...
判別三連之三 Spark 分布式實現貝葉斯判別
假 設事 件b1,b2.bn是 樣本空間 的乙個 分割,且 他們各自 的概率為 p b1 p b2 p bn 假設事件 b 1,b 2.b n 是樣本空間 的乙個分割,且他們各自的概率為p b 1 p b 2 p b n 假設事件b1 b2 bn 是 樣本空間 的乙個 分割,且 他們各自 的概率為 ...