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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[TJOI2011] 卡片(网络流 + 质因子优化建图)

發(fā)布時間:2023/12/3 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [TJOI2011] 卡片(网络流 + 质因子优化建图) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

problem

luogu-P2065

solution

這個拿走一組共兩張卡片的操作其實就是一個匹配。

直接兩個數(shù)的最大公約數(shù)大于 111 就建一條邊,跑二分圖匹配最大流即可。

然而如果直接枚舉兩個數(shù)然后算他們的 gcd\text{gcd}gcd ,時間復(fù)雜度 O(Tn2log?V)O(Tn^2\log V)O(Tn2logV)TLE\text{TLE}TLE

又不能預(yù)處理任意兩個數(shù)的 gcd\text{gcd}gcd,這個數(shù)字 ∈(1,1e7)\in(1,1e7)(1,1e7) 實在是太大了。

這里很巧妙,任何數(shù)都可以拆成若干個質(zhì)數(shù)的冪,兩個數(shù)的 gcd>1\text{gcd}>1gcd>1 無非就是兩個數(shù)有相同的某些個質(zhì)因子。

所以我們可以預(yù)處理出 1e71e71e7 以內(nèi)的所有質(zhì)數(shù),這并不多,然后將一個數(shù)和其質(zhì)因子連邊。

只顯然每張卡片只能拿走一次,流量與源匯點之間為 111 即可。

這樣時間復(fù)雜度就是 O(Tnn)O(Tn\sqrt{n})O(Tnn?) ,網(wǎng)絡(luò)流就沒考慮反正是 O(O(O( 能過 )))

code

#include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxm 800005 int T, m, n, s, t, cnt = -1, tot; struct node { int to, nxt, flow; }E[maxm]; int b[maxn], r[maxn], head[maxn], cur[maxn], dep[maxn]; queue < int > q;int gcd( int x, int y ) {if( ! y ) return x;else return gcd( y, x % y ); }void addedge( int u, int v, int w ) {E[++ cnt] = { v, head[u], w }, head[u] = cnt;E[++ cnt] = { u, head[v], 0 }, head[v] = cnt; }bool bfs() {memset( dep, 0, sizeof( dep ) );memcpy( cur, head, sizeof( head ) );dep[s] = 1; q.push( s );while( ! q.empty() ) {int u = q.front(); q.pop();for( int i = head[u];~ i;i = E[i].nxt ) {int v = E[i].to;if( ! dep[v] and E[i].flow ) {dep[v] = dep[u] + 1;q.push( v );}}}return dep[t]; }int dfs( int u, int cap ) {if( u == t or ! cap ) return cap;int flow = 0;for( int i = cur[u];~ i;i = E[i].nxt ) {cur[u] = i; int v = E[i].to;if( dep[v] == dep[u] + 1 ) {int w = dfs( v, min( cap, E[i].flow ) );if( ! w ) continue;E[i ^ 1].flow += w;E[i].flow -= w;flow += w;cap -= w;if( ! cap ) break;}}return flow; }int dinic() {int ans = 0;while( bfs() ) ans += dfs( s, 1e9 );return ans; }#define maxp 10000005 int prime[maxp], vis[maxp], num[maxp]; int cntp; void sieve() {for( int i = 2;i < 1e7;i ++ ) {if( ! vis[i] ) prime[++ cntp] = i;for( int j = 1;j <= cntp and i * prime[j] < 1e7;j ++ ) {vis[i * prime[j]] = 1;if( i % prime[j] == 0 ) break;}} } void divide( int id, int val ) {for( int i = 1;i <= cntp and prime[i] <= val;i ++ ) if( val % prime[i] == 0 ) {if( ! num[prime[i]] ) num[prime[i]] = ++ tot;if( id <= m ) addedge( id, num[prime[i]], 1e9 );else addedge( num[prime[i]], id, 1e9 );while( val % prime[i] == 0 ) val /= prime[i];} }int main() {sieve(); tot = 1001;scanf( "%d", &T );while( T -- ) {memset( head, -1, sizeof( head ) ); cnt = -1;scanf( "%d %d", &m, &n );s = 0, t = n + m + 1;for( int i = 1;i <= m;i ++ ) scanf( "%d", &b[i] );for( int i = 1;i <= n;i ++ ) scanf( "%d", &r[i] );for( int i = 1;i <= m;i ++ ) divide( i, b[i] );for( int i = 1;i <= n;i ++ ) divide( i + m, r[i] );for( int i = 1;i <= m;i ++ ) addedge( s, i, 1 );for( int i = 1;i <= n;i ++ ) addedge( i + m, t, 1 );printf( "%d\n", dinic() );}return 0; }

總結(jié)

以上是生活随笔為你收集整理的[TJOI2011] 卡片(网络流 + 质因子优化建图)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。