【bzoj3158】千钧一发 题解
【bzoj3158】千钧一发
1、题面描述:
题目背景
在你正确回答表达式的值以后,石板又出现了新的状况﹐然而这次情况十分紧急,如果无法做出正确的选择,Katherine 皇后很可能再也无法和 Kanari 国王在一起了。
题目描述
石板上突然出现 \(n\) 个奇怪的装置,Kanari 国王仔细观察发现每个装置上面都写有两个正整数,我们记第 \(i\) 个装置上的两个正整数分别为 \(a_i\) 和 \(b_i\) 。其中 \(a_i\) 表示这个装置的特征值,\(b_i\) 表示这个装置蕴含的能量值。现在请你在这 \(n\) 个装置中选择一部分出来,使得选择的任意两个装置 \(i\) 和 \(j(i≠j)\) 至少满足下面两个条件之一:
1.不存在正整数 \(T\) 使得 \(a_i^2 + a_j^2 = T ^ 2\)
2.\(a_i\)和 \(a_j\) 有大于 \(1\) 的公因子。
你的目标就是使得选出来装置的能量值总和最大,如果你回答正确,说不定石板会按照它所说的,将 Katharon 国最珍贵的财产交出来,否则国王,皇后以及你的小命都将难保。
输入格式
第一行一个正整数 \(n\) 。
第二行共包括 \(n\) 个正整数,第 \(i\) 个正整数表示 \(a_i\) 。
第三行共包括 \(n\) 个正整数,第 \(i\) 个正整数表示 \(b_i\) 。
输出格式
共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值。
样例输入
4
3 4 5 12
9 8 30 9
样例输出
39
数据规模与约定
\(1 \leq n \leq 10^3,1 \leq a_i,b_i \leq 10^6\)
首先看到题面,我们可以发现:对于每个点都会有约束的情况。
如果在每个点处查询已有的序列(像是求最长上升子序列那样),时间复杂度直飚到 \(O(n ^ 3log{n})\)。
这显然是无法接受的,对于这种每个点选或不选,且任意两个选择的点之间有着复杂约束关系的题,我们可以考虑用网络流去做。
对于网络流的题,最重要的是建模。
想象一个有着一堆水管的空地,有一个源源不断出水的源点,有一个源源不断进水的汇点。
那我们考虑这些的对应关系。
对于这个题来说,最大流显然是不是很好找的,我们可以反着想。
我们不妨假设最开始的所有点都在集合当中。所有的价值都计入答案。我们只需要的是踢出不合法的点,之后再更新答案即可。
换算成网络流的话来说,就是通过建模表示点与点之间的对应关系,求出最小割,即是我们要舍弃的最小损失,剩下的就是最大贡献。
考虑如何建模:
对于建模来说,最重要也是最难的是表示好点与点之间的关系。
我们不妨考虑两个互相排斥的点,两个点通过一定的手段(连边、连接虚点之类的)来保证一个取了,另一个一定不会取。
回到这个题,我们考虑一下两点取舍的贡献,即为题目中所给的 \(b\) 数组。设这两个点为 \(i\),\(j\),我们直接将这两个点用一条边连起来, 那么我们求最小割时,割的一定是权值为 \(b_i\) 或 \(b_j\) 这两条边中的一个,那么,我们可不可以把表示这两点关系的边的权值附成 \(min(b_i,b_j)\) 呢?
我认为是不能的。
在割掉这条边的时候,\(i\) 和 \(j\) 之间的对应关系被破坏了,这是我们不想看到的,相对应的,为了维护 \(i\) 和 \(j\) 之间的关系,我们通常把这条边权值设为 \(INF\) ,这样就不会被割了。
回到刚才,既然这两点之间的边无法将权值设为 \(min(b_i,b_j)\) ,那这两个东西设到哪里呢?
自然而然地,我们想到了源点和汇点。
于是我们将每个点拆成两个,记录一个入点的 \(id\) ,一个出点的 \(iv\) ,源点连入点,出点连汇点,权值都为 \(b\) ,不符合条件的点与点之间连一条权值为 \(INF\) 的边(从一个点的入点到另一个点的出点)。
所以,我们就建好模了。
最后答案统计时,因为权值为 \(b\) 的边建了两次,在统计答案时 \(/ 2\) 即可。
好了,现在你已经完成了这个题的大部分了 ,剩下的就是再敲一个求最大流(也就是最小割)的板子就可以愉快地 A 掉这个题了。
最后,代码附上:
#include<bits/stdc++.h>
#define lid (id << 1)
#define rid ((id << 1) | 1)
#define int long long
#define Blue_Archive return 0
#define ent putchar_unlocked('\n')
#define con putchar_unlocked(' ')
using namespace std;
const int N = 1e4 + 7;
const int M = 2e6 + 7;
const int INF = 4557430888798830399;
int n;
int s;
int t;
int tim;
int ans;
int tot = 1;
int h[N];
int a[N];
int b[N];
int w[M];
int in[N];
int iv[N];
int to[M];
int nxt[M];
int dis[N];
int cur[N];
inline int read()
{
int x = 0;
char c = getchar_unlocked();
for(;!isdigit(c);c = getchar_unlocked());
for(;isdigit(c);x = x * 10 + c - 48,c = getchar_unlocked());
return x;
}
inline void write(int x)
{
if(x < 0) putchar_unlocked('-'),x = -x;
if(x > 9) write(x / 10);
putchar_unlocked(x % 10 + '0');
}
inline void add(int a,int b,int c)
{
to[++ tot] = b,w[tot] = c,nxt[tot] = h[a],h[a] = tot;
to[++ tot] = a,w[tot] = 0,nxt[tot] = h[b],h[b] = tot;
}
inline bool bfs()
{
memset(dis,0x3f,sizeof(dis));
queue<int> q;
q.push(s);
dis[s] = 0;
cur[s] = h[s];
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = h[u];i;i = nxt[i])
{
if(w[i] && dis[to[i]] == INF)
{
q.push(to[i]);
cur[to[i]] = h[to[i]];
dis[to[i]] = dis[u] + 1;
if(to[i] == t) return 1;
}
}
}
return 0;
}
inline int dfs(int x,int sum)
{
if(x == t) return sum;
int k,res = 0;
for(int i = cur[x];i && sum;i = nxt[i])
{
cur[x] = i;
if(w[i] && dis[to[i]] == dis[x] + 1)
{
k = dfs(to[i],min(sum,w[i]));
if(k == 0) dis[to[i]] = INF;
w[i] -= k;
w[i ^ 1] += k;
res += k;
sum -= k;
}
}
return res;
}
signed main()
{
n = read();
s = N - 1;
t = N - 2;
for(int i = 1;i <= n;i ++) a[i] = read();
for(int i = 1;i <= n;i ++)
{
in[i] = ++ tim;
iv[i] = tim + n;
b[i] = read();
ans += b[i];
add(s,in[i],b[i]);
add(iv[i],t,b[i]);
}
for(int i = 1,op;i <= n;i ++)
{
for(int j = 1;j < i;j ++)
{
if(__gcd(a[i],a[j]) != 1) continue;
op = a[i] * a[i] + a[j] * a[j];
if((int)sqrt(op) * (int)sqrt(op) != op) continue;
add(in[i],iv[j],INF);
add(in[j],iv[i],INF);
}
}
while(bfs()) ans -= dfs(s,INF) / 2;
write(ans);ent;
Blue_Archive;
}

浙公网安备 33010602011771号