P12026 [USACO25OPEN] Compatible Pairs S
题目描述
在遥远的乡村,农夫约翰的奶牛并非普通的农场动物——它们隶属于一个秘密的奶牛情报网络。每头奶牛都有一个由精英密码学家精心分配的ID号码。但由于农夫约翰随意的标记系统,部分奶牛出现了重复ID的情况。
农夫约翰记录到共有 \(N\)(\(1\le N\le 2\cdot 10^5\))个不同的ID号码,对于每个唯一ID \(d_i\)(\(0\le d_i\le 10^9\)),有 \(n_i\)(\(1\le n_i\le 10^9\))头奶牛共享该ID。
奶牛们只能成对交流,它们的加密通信有一个严格规则:两头奶牛仅当不是同一头牛且它们的ID号码之和等于 \(A\) 或 \(B\)(\(0\le A\le B\le 2\cdot 10^9\))时才能交换信息。每头奶牛同一时间只能参与一次对话(即不能同时属于多对通信组合)。
农夫约翰希望最大化互不干扰的通信对数来确保最佳信息流通。你能计算出最多可以同时建立多少对通信吗?
输入格式
第一行包含 \(N\)、\(A\)、\(B\)。
接下来 \(N\) 行每行包含 \(n_i\) 和 \(d_i\)。所有 \(d_i\) 均不相同。
输出格式
可同时建立的最大互不干扰通信对数。
注意:由于涉及大整数运算,可能需要使用 64 位整数类型(如C/C++中的 long long
)。
输入输出样例 #1
输入 #1
4 4 5
17 2
100 0
10 1
200 4
输出 #1
118
说明/提示
解释:
ID为 \(0\) 的奶牛可与 ID 为 \(4\) 奶牛通信(ID 之和为 \(4\))。由于共有 \(100\) 头 ID \(0\) 的奶牛和 \(200\) 头 ID \(4\) 的奶牛,最多可组成 \(100\) 对通信组合。
ID 为 \(4\) 的奶牛还可与 ID 为 \(1\) 的奶牛通信(ID 之和为\(5\))。此时剩余 \(100\) 头 ID \(4\) 的奶牛和 \(10\) 头 ID \(1\) 的奶牛可组成 \(10\) 对通信组合。
最后,ID 为 \(2\) 的奶牛可与其他同 ID 奶牛通信。\(17\) 头 ID \(2\) 的奶牛最多可组成 \(8\) 对通信组合(\(\lfloor17/2\rfloor=8\))。
总计 \(100+10+8=118\) 对通信组合,可以证明这是最大可能值。
- 测试点 \(3\sim4\):\(A=B\)。
- 测试点 \(5\sim7\):\(N\le 1000\)。
- 测试点 \(8\sim12\):无额外限制。
解题报告
(施工单:补全建模后最终情况的证明和拓扑排序的正确性证明)
直接图论建模!!!
对于一个 \(\text{id}\),我们建出以下两条边:
- \(\text{id}<A,\text{id} \rightarrow A-\text{id}\)
- \(\text{id}<B,\text{id} \rightarrow B-\text{id}\)
有对称性可知,也有这两条边:
- \(A-\text{id} \rightarrow A\)
- \(B-\text{id} \rightarrow B\)
所以这是个无向图。
由于题目保证每一个 \(\text{id}\) 唯一,那么每一个和为 \(A\) 的数对是唯一的,每一个和为 \(B\) 的数对也是唯一的,所以最后我们的图一定是一个可能带着自环的链。
直接拓扑排序。
代码如下:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int INF=0x3f3f3f3f;
const int N=201100;#define ckmax(x,y) ( x=max(x,y) )
#define ckmin(x,y) ( x=min(x,y) )inline int read()
{int f=1,x=0; char ch=getchar();while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); }return f*x;
}int n,S1,S2;
int ans;
int w[N],p[N];
vector<int> e[N];
map<int,int> col;inline void toposort()
{queue<int> q;for(int i=1;i<=n;i++)if(e[i].size()==1)q.push(i);while(!q.empty()){int u=q.front(); q.pop();for(int i=0;i<e[u].size();i++){int v=e[u][i];if(u==v){ans+=w[u]/2;w[u]%=2;continue;}if(w[v]){int tmp=min(w[u],w[v]);ans+=tmp,w[u]-=tmp,w[v]-=tmp;q.push(v);}}}
}signed main()
{n=read(),S1=read(),S2=read();for(int i=1;i<=n;i++){w[i]=read(),p[i]=read();col[p[i]]=i;}for(int i=1;i<=n;i++){if(p[i]<=S1 && col[S1-p[i]])e[i].push_back(col[S1-p[i]]);if(S1==S2) continue;if(p[i]<=S2 && col[S2-p[i]])e[i].push_back(col[S2-p[i]]);}toposort();printf("%lld",ans);return 0;
}