洛谷P3652 csh和zzy的戰爭 題解

2022-09-14 17:45:22 字數 2740 閱讀 5156

給定一些貨源地,一些中轉島,以及乙個終點——軍事基地。

貨源地分為兩種,普通貨和特殊貨。

對於中轉島 \(i\) ,最多可以中轉 \(w_i\) 件貨物,中轉島發向另乙個中轉島或軍事基地的貨物分別不能超過 \(d_i\) 。

上面貨物皆指普通貨物,特殊貨物不會受到限制。

中轉島之間有 \(e\) 條航道,航道 \(i\) 有邊權。開闢航線 \(u-v\) 的代價是 \(u\) 和 \(v\) 之間的最短路。

最後全域性的代價是航線代價的最大值。

要求在所有貨物都能夠到達軍事基地的前提下,最小代價是多少。

看到代價是最大值,要求其最小,考慮可以二分。將代價小於等於二分答案 \(\text\) 的航線全都加進去,看是否能將所有貨物都送達軍事基地。二分正確性顯然。

分別考慮特殊貨物和普通貨物。

首先考慮特殊貨物,只要貨源地和軍事基地相連,即可全部運往軍事基地。我們將所有航線全部連上,並連反邊(基地連向中轉島,中轉島連向貨源地)。中轉島間邊權設為航線開闢代價。從軍事基地開始使用最短路演算法,最小化到各個貨源地的路徑上的最大邊權。可以發現將所有特殊貨源地的答案取 \(\text\) 是二分下界。

至於如何求出兩島間航線代價,使用 \(n^3\) 的最短路即可。

然後考慮如何求是否所有普通貨物都可到達軍事基地。

使用網路流求最大流。貨源地連中轉島容量為 \(\text\) ,中轉島之間和中轉島到軍事基地的邊容量為 \(d\) ,將中轉島拆點控制經過島的流量不超過 \(w\) 。

隨後跑最大流就好了,此題解決。

#include #include #include #include #include #define int long long

#define mp make_pair

#define val lim

#define pb push_back

using namespace std;

int read()

while(ch >= '0' && ch <= '9')

return a*x;

}const int n=1e6+7,inf = 1e9+7;

int n,m,x,e,a[n],w[n],d[n],b[n],m,s,t;

vectorg[307];

int mp[500][500],dis[n],vis[n];

int head[n],go[n],nxt[n],cnt,lim[n],cur[n];

void add(int u,int v,int w)

struct nodeedge[n];

void dij(int pos)

dis[u] = -q.top().first;q.pop();vis[u] = 1;

for(int e = head[u];e;e = nxt[e]) }}

bool bfs()

} return dis[t];

}int dfs(int u,int limit)

return ret;

}bool check(int limit)

} for(int i = 1;i <= m && edge[i].w <= limit;i ++)

// puts("!");printf("sum=%d\n",sum);

for(int i = s;i <= t;i ++) cur[i] = head[i];

while(bfs())

return !sum;//sum=0說明所有貨物都可以送到軍事基地

}bool cmp(node a,node b)

signed main()

b[i] = read();if(b[i]) add(n+x+m+1,n+x+i,0);

} for(int i = 1;i <= e;i ++)

for(int i = 1;i <= m;i ++) for(int j = 1;j <= m;j ++) if(!mp[i][j]) mp[i][j] = inf; else if(i!=j) add(n+x+i,n+x+j,mp[i][j]);

//邊先連上,為處理特殊貨物做準備,顯然不需要連那些本來沒有直接連邊的航線。連線他們不會使答案更優。

for(int k = 1;k <= m;k ++) for(int i = 1;i <= m;i ++) for(int j = 1;j <= m;j ++) mp[i][j] = min(mp[i][j],mp[i][k]+mp[k][j]);

dij(n+m+x+1);int l = 0,r,mid;//跑最短路

for(int i = n+1;i <= n+x;i ++) l = max(l,dis[i]);//賦值下界

memset(head,0,sizeof(head)); cnt = 1;s = 0,t = n+2*m+1;

for(int i = 1;i <= m;i ++) for(int j = i+1;j <= m;j ++) if(mp[i][j] < inf) edge[++m] = (node);

//把所有航線拿出來排序

sort(edge+1,edge+1+m,cmp);r = inf;

while(l>1;

if(check(mid)) r = mid;

else l = mid + 1;

// printf("mid=%d\n",mid);

} if(l != inf) printf("%lld",l);

else printf("-1");

}

洛谷 P2646 數數zzy

zzy自從數學考試連續跪掉之後,上數學課就從來不認真聽了 事實上他以前也不認真聽 於是他開始在草稿紙上寫寫畫畫,比如寫一串奇怪的字串。然後他決定理 性 愉 悅 一下 統計這串字串當中共有多少個為 zzy 的子串行 注意是子串行而非子串 但是由於他寫的字串實在是太長啦,而且他是個超級大蒟蒻,根本就數不...

洛谷 P2424 約數和

1s 128mb smart最近沉迷於對約數的研究中。對於乙個數x,函式f x 表示 x 所有約數的和。例如 f 6 1 2 3 6 12 對於乙個 x smart可以很快的算出f x 現在的問題是,給定兩個正整數x,y x,smart希望盡快地算出f x f x 1 f y 的值,你能幫助smar...

洛谷P2068 統計和

給定乙個長度為 n n leq 100000 初始值都為 0 的序列,x x leq 10000 次的修改某些位置上的數字,每次加上乙個數,然後提出 y y leq 10000 個問題,求每段區間的和。時間限制 1 秒。輸入格式 第一行 1 個數,表示序列的長度 n 第二行 1 個數,表示操作的次數...