专栏文章
省队集训-0424模拟赛
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mip039yx
- 此快照首次捕获于
- 2025/12/03 03:58 3 个月前
- 此快照最后确认于
- 2025/12/03 03:58 3 个月前
A.图上的游戏
题意:
有一张图, 个点,每个点有颜色 ,随机产生 条有向边(可重可自环)。然后 两个人博弈,轮流操作,一次可以将一个颜色为 的点染成 或 ,直到不存在颜色为 的点。最终分数为:所有两端颜色不同的边中, 的边的个数,减去 的边的个数。 想要最大化得分, 想要最小化得分。
给定 ,以及 个点的颜色。,求当只保留 的点(即 ),且 时,对于所有的 种情况,博弈分数的总和为多少。
。
Sol:
设 表示一个点的出度减入度,则分数为 。图定下来后 就确定了,于是两人会按照 降序把所有 的点排序,然后贪心选择。
考虑如何计算分数总和。
首先, 的点本身不影响总和,只影响方案数,因为把所有边都反转它就要做负贡献,抵消掉。
然后我们可以按 降序,枚举所有的点可能的出度入度个数的对,总共有 种,然后做一个背包(因为总出度、入读都是 ),维护方案数和总和。
首先, 的点本身不影响总和,只影响方案数,因为把所有边都反转它就要做负贡献,抵消掉。
然后我们可以按 降序,枚举所有的点可能的出度入度个数的对,总共有 种,然后做一个背包(因为总出度、入读都是 ),维护方案数和总和。
我们可以把 条有向边,看成两个独立的长为 的出点、入点序列,于是贡献系数就可以 计算:
设出度入度分别为 ,已经用了 个 的点, 的入度, 的出度,维护方案数、总和。枚举 个数 ,有 ,乘上 的系数,转移到 ,总和加上 。
设出度入度分别为 ,已经用了 个 的点, 的入度, 的出度,维护方案数、总和。枚举 个数 ,有 ,乘上 的系数,转移到 ,总和加上 。
然后是统计答案:
注意我们只对 的点做了背包。设 为 的点的个数。首先要乘上 (划分多组的组合数系数)。考虑剩下的点的出、入度,先乘上 ,表示把剩下的点当成特殊的一组,然后乘上 的方案数。
注意我们只对 的点做了背包。设 为 的点的个数。首先要乘上 (划分多组的组合数系数)。考虑剩下的点的出、入度,先乘上 ,表示把剩下的点当成特殊的一组,然后乘上 的方案数。
由于转移时有 ,所以总复杂度 。
Code:
CPP#include <bits/stdc++.h>
#define pii pair <int,int>
#define fi first
#define se second
#define mkp make_pair
using namespace std;
const int N = 55,mod = 1e9 + 7;
int n,m,cnt,f[N][N][N],g[N][N][N],inv[N],fac[N],ifac[N],mi[N << 1],col[N];
pii p[N * N];
bool cmp(pii x,pii y){return abs(x.fi - x.se) > abs(y.fi - y.se);}
int main()
{
inv[1] = fac[0] = ifac[0] = 1;
for(int i = 2;i < N;i++) inv[i] = mod - 1LL * (mod / i) * inv[mod % i] % mod;
for(int i = 1;i < N;i++) fac[i] = 1LL * fac[i - 1] * i % mod;
for(int i = 1;i < N;i++) ifac[i] = 1LL * ifac[i - 1] * inv[i] % mod;
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i = 0;i <= m;i++)
for(int j = 0;j <= m;j++)
p[++cnt] = mkp(i,j);
sort(p + 1,p + cnt + 1,cmp);
f[0][0][0] = 1;
for(int i = 1;i <= cnt;i++)
{
int a = p[i].fi,b = p[i].se,c = abs(a - b);
for(int j = n;j >= 0;j--)
for(int k = 1,s = 1;k <= j && k * a <= m && k * b <= m;k++)
{
s = 1LL * s * inv[k] % mod * ifac[a] % mod * ifac[b] % mod;
for(int x = k * a;x <= m;x++)
for(int y = k * b;y <= m;y++)
{
int v = 1LL * f[j - k][x - k * a][y - k * b] * s % mod;
f[j][x][y] = (f[j][x][y] + v) % mod;
g[j][x][y] = (g[j][x][y] + 1LL * g[j - k][x - k * a][y - k * b] * s % mod) % mod;
if(k & 1)
if(j & 1) g[j][x][y] = (g[j][x][y] + 1LL * v * c % mod) % mod;
else g[j][x][y] = (g[j][x][y] - 1LL * v * c % mod + mod) % mod;
}
}
}
for(int i = 1;i <= n;i++) scanf("%d",&col[i]);
for(int i = 1,e = 0;i <= n;i++)
{
e += (col[i] == 2),mi[0] = 1;
for(int j = 1;j <= 2 * m;j++) mi[j] = 1LL * mi[j - 1] * (i - e) % mod;
for(int j = 1;j <= m;j++)
{
int ans = 0;
for(int x = 0;x <= j;x++)
for(int y = 0;y <= j;y++)
ans = (ans + 1LL * g[e][x][y] * fac[e] % mod * fac[j] % mod * fac[j] % mod * mi[j - x + j - y] % mod * ifac[j - x] % mod * ifac[j - y] % mod) % mod;
ans = 1LL * ans * (mod / 2 + 1) % mod;
printf("%d ",ans);
}
puts("");
}
return 0;
}
B.修理:
题意:
有一个序列 ,和一个初始为 的变量 ,可以进行一下两种操作:
1.
2.
定义这个序列的代价,为最小的操作次数使得 全零。
给定一个长为 的序列,每次询问一个子区间 的代价,强制在线。
Sol:
一定要大于等于 ,然后 的 有 的贡献, 的有 的贡献。
设 为 ,则 的 贡献一定为 ,可以只考虑 的点。
设 为 ,则 的 贡献一定为 ,可以只考虑 的点。
扫描 ,对每个 维护答案,用可持久化数据结构存答案,然后在线回答。考虑 时对答案的影响。
贡献其实可以写成 ,设 ,则要最小化 ,答案为 。
贡献其实可以写成 ,设 ,则要最小化 ,答案为 。
设最优 为使得 最小时最小的 。不难发现随着区间扩展, 不增而且最多减少 ,因为后面一个求和式最多加一,而且取得最优的 不降。
同时,我们一定可以找出一个分界点 ,使得 的区间 , 的区间 不变,证明如下:
同时,我们一定可以找出一个分界点 ,使得 的区间 , 的区间 不变,证明如下:
设 ,且 更新。设 ,显然有 ,因此 。
若 则 一定更新; 考虑 。注意到新加入一个数会让 的一个后缀减一,所以较小位置与较大位置的 之差只会扩大。
所以 ,因此 也会更新。
若 则 一定更新; 考虑 。注意到新加入一个数会让 的一个后缀减一,所以较小位置与较大位置的 之差只会扩大。
所以 ,因此 也会更新。
考虑求出 。
可以证明 在后续是没有影响的。首先有 ,否则 , 也会更新。
又因为 递增,所以 一定有 ,所以 后面只有 的贡献,可以打上答案永久 的标记然后把 删掉。
可以证明 在后续是没有影响的。首先有 ,否则 , 也会更新。
又因为 递增,所以 一定有 ,所以 后面只有 的贡献,可以打上答案永久 的标记然后把 删掉。
设受删除影响后的 为 。假设加入 后, 最小的一个小于 的位置为 。
如果不存在这样的 ,则 不改变();否则, 为 。下面给出证明。
如果不存在这样的 ,则 不改变();否则, 为 。下面给出证明。
首先可以归纳证明,每次删掉 后, 。
考虑加入 后一个满足 的位置,显然有 。
如果 ,则答案一定会更新;
否则 ,把 改成 一定更优。因为 ,而由于 递增,所以上文中标记只与区间端点有关。
考虑加入 后一个满足 的位置,显然有 。
如果 ,则答案一定会更新;
否则 ,把 改成 一定更优。因为 ,而由于 递增,所以上文中标记只与区间端点有关。
对于 中一个 的位置 ,设 表示 ,则显然 ,因为 中后面的和式值不变。
显然 随 增大而减小,而 ,所以 。
显然 随 增大而减小,而 ,所以 。
考虑用一棵值域线段树维护 中未被删除的值,以维护 , 可以在上面线段树二分求得。再对每个 开一个可持久化线段树存下标记即可。
时空复杂度 。
代码里好像把 全部取负数了、、
时空复杂度 。
代码里好像把 全部取负数了、、
Code:
CPP#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
const int N = 2e5 + 5,INF = 2e9;
int n,Q,T,c[60],s[60],id[N],nxt[N],pos[N],rt[N][60],q[N][60];
ll a[N];
struct SgT1
{
#define ls (x << 1)
#define rs (ls | 1)
int minn[N << 2],maxn[N << 2],tag[N << 2];
void upd(int x,int v){maxn[x] += v,tag[x] += v;}
void pushdown(int x){if(tag[x]) upd(ls,tag[x]),upd(rs,tag[x]),tag[x] = 0;}
void pushup(int x){minn[x] = min(minn[ls],minn[rs]),maxn[x] = max(maxn[ls],maxn[rs]);}
void update1(int x,int l,int r,int p,int a,int b)
{
if(l == r) return (void)(minn[x] = a,maxn[x] += b);
pushdown(x);
if(p <= mid) update1(ls,l,mid,p,a,b);
else update1(rs,mid + 1,r,p,a,b);
pushup(x);
}
void update2(int x,int l,int r,int L,int R,int v)
{
if(L <= l && r <= R) return upd(x,v);
pushdown(x);
if(L <= mid) update2(ls,l,mid,L,R,v);
if(R > mid) update2(rs,mid + 1,r,L,R,v);
pushup(x);
}
int find(int x,int l,int r,int L,int R)
{
if(maxn[x] <= 0) return 0;
if(l == r) return l;
pushdown(x);
if(L <= l && r <= R)
{
if(maxn[ls] > 0) return find(ls,l,mid,L,R);
return find(rs,mid + 1,r,L,R);
}
int ret = 0;
if(L <= mid && (ret = find(ls,l,mid,L,R))) return ret;
if(R > mid) ret = find(rs,mid + 1,r,L,R);
return ret;
}
int query(int x,int l,int r,int L,int R)
{
if(L <= l && r <= R) return minn[x];
pushdown(x);
if(R <= mid) return query(ls,l,mid,L,R);
if(L > mid) return query(rs,mid + 1,r,L,R);
return min(query(ls,l,mid,L,R),query(rs,mid + 1,r,L,R));
}
#undef ls
#undef rs
} tr1;
struct SgT2
{
int tot,sum[N * 20],ls[N * 20],rs[N * 20];
int update(int o,int l,int r,int p)
{
int x = ++tot;
sum[x] = sum[o] + 1;
if(l == r) return x;
if(p <= mid) ls[x] = update(ls[o],l,mid,p),rs[x] = rs[o];
else rs[x] = update(rs[o],mid + 1,r,p),ls[x] = ls[o];
return x;
}
int query(int x,int l,int r,int L,int R)
{
if(!x) return 0;
if(L <= l && r <= R) return sum[x];
if(R <= mid) return query(ls[x],l,mid,L,R);
if(L > mid) return query(rs[x],mid + 1,r,L,R);
return query(ls[x],l,mid,L,R) + query(rs[x],mid + 1,r,L,R);
}
} tr2;
int main()
{
freopen("repair.in","r",stdin);
freopen("repair.out","w",stdout);
scanf("%d%d%d",&n,&Q,&T);
for(int i = 1;i <= n;i++) scanf("%lld",&a[i]);
for(int i = 1;i <= n;i++) c[__lg(a[i])]++;
for(int i = 0;i < 60;i++) s[i] = (i ? s[i - 1] : 0) + c[i];
for(int i = 0,id = 0;i < 60;i++) for(int j = 1;j <= c[i];j++) tr1.update1(1,1,n,++id,INF,1 - j);
fill(pos + 1,pos + n + 1,n + 1);
for(int i = n;i >= 1;i--)
{
int t = __lg(a[i]);
ll r = a[i] - (1LL << t);
if(r >= c[t]) continue;
id[i] = (t ? s[t - 1] : 0) + r + 1;
nxt[i] = pos[id[i]],pos[id[i]] = i;
}
memset(pos,0,sizeof(pos));
for(int i = 1;i <= n;i++)
{
memcpy(rt[i],rt[i - 1],sizeof(rt[i]));
memcpy(q[i],q[i - 1],sizeof(q[i]));
int t = __lg(a[i]);
ll r = a[i] - (1LL << t);
q[i][t]++;
if(r >= c[t]) continue;
if(!pos[id[i]]) tr1.update1(1,1,n,id[i],i,0),pos[id[i]] = i;
tr1.update2(1,1,n,id[i],s[t],1);
int v = tr1.find(1,1,n,id[i],s[t]);
if(v)
{
int p = tr1.query(1,1,n,(t ? s[t - 1] : 0) + 1,v);
rt[i][t] = tr2.update(rt[i][t],1,n,p);
if(nxt[p] <= i) tr1.update1(1,1,n,id[p],nxt[p],0),pos[id[p]] = nxt[p];
else tr1.update1(1,1,n,id[p],INF,0),pos[id[p]] = 0;
tr1.update2(1,1,n,id[p],s[t],-1);
}
}
ll lst = 0,l,r;
for(int i = 1,t;i <= Q;i++)
{
scanf("%lld%lld",&l,&r);
if(T == 2) l ^= lst,r ^= lst;
if(l > r) swap(l,r);
for(t = 59;q[r][t] - q[l - 1][t] == 0;t--);
lst = (1LL << t) + r - l + 1 + q[r][t] - q[l - 1][t] - tr2.query(rt[r][t],1,n,l,r);
printf("%lld\n",lst);
}
return 0;
}
C.人员调度2
题意:
要做二分图匹配,左右各 个点, 匹配贡献为 。此外有 个特殊边 ,表示 匹配有额外 的贡献。
给定 ,,回答恰好匹配 对时候的最大值。
。
Sol:
拆位看基础贡献,其实是 。直接跑 轮增广路的话是 的。
法一:
观察匈牙利算法的增广路,发现要么从左边直接到右边,要么中间经过一些匹配过的点。
值域比较小,直接每次 处理出和一个点最优的为匹配点,然后 floyd 跑已匹配点的最短路。
。
值域比较小,直接每次 处理出和一个点最优的为匹配点,然后 floyd 跑已匹配点的最短路。
。
法二:
首先每个点只用保留和自己连接的所有边中前 大的;
其次,在上述保留的边中,只用取前 条。因为用一条边会尽调与之相连的边,最多 条。所以可以通过调整法把每一条边都变成前 大的。
其次,在上述保留的边中,只用取前 条。因为用一条边会尽调与之相连的边,最多 条。所以可以通过调整法把每一条边都变成前 大的。
Code:
CPP#include <bits/stdc++.h>
#define pii pair <int,int>
#define fi first
#define se second
#define mkp make_pair
#define pb push_back
#define il inline
using namespace std;
typedef long long ll;
il int read()
{
int x = 0;
char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
return x;
}
const int N = 1e5 + 5,M = 305,V = (1 << 12),INF = 2e9;
int n,m,K;
namespace AAA
{
int cnt,a[N],b[N],d1[N],d2[N],id1[N],id2[N],used[N],vis[N];
int cnt1[V],cnt2[V],cur1[V],cur2[V],s1[V][M],s2[V][M];
vector <int> t[V],w1[V],w2[V],p[N];
struct Edge{int x,y,z;};
vector <Edge> e,p1[N],p2[N];
bool cmp1(Edge x,Edge y){return x.z > y.z;}
bool cmp2(Edge x,Edge y){return x.x < y.x;}
struct Flow
{
int tot = 1,S,T,head[N],to[N],val[N],cst[N],nxt[N],pre[N],dis[N],in[N];
queue <int> q;
il void add_(int x,int y,int z,int c){to[++tot] = y,val[tot] = z,cst[tot] = c,nxt[tot] = head[x],head[x] = tot;}
il void add_edge(int x,int y,int z,int c){add_(x,y,z,c),add_(y,x,0,-c);}
il void spfa()
{
memset(dis,-127,sizeof(int) * (cnt + 1));
q.push(S),dis[S] = 0,in[S] = 1;
while(!q.empty())
{
int x = q.front();
q.pop(),in[x] = 0;
for(int i = head[x],y;i;i = nxt[i])
if(val[i] && dis[y = to[i]] < dis[x] + cst[i])
{
dis[y] = dis[x] + cst[i],pre[y] = i;
if(!in[y]) q.push(y),in[y] = 1;
}
}
}
il void ek()
{
int ans = 0;
while(K--)
{
spfa(),ans += dis[T];
for(int i = T;i != S;i = to[pre[i] ^ 1]) val[pre[i]]--,val[pre[i] ^ 1]++;
printf("%d ",ans);
}
puts("");
}
} g;
void Main()
{
for(int i = 1;i <= n;i++) a[i] = read();
for(int i = 1;i <= n;i++) b[i] = read();
for(int i = 1,x,y,z;i <= m;i++)
{
x = read(),y = read(),z = read() + 2 * (a[x] | b[y]);
p1[x].pb((Edge){x,y,z}),p2[y].pb((Edge){x,y,z});
}
for(int i = 1;i <= n;i++) w1[a[i]].pb(i);
for(int i = 1;i <= n;i++) w2[b[i]].pb(i);
for(int i = 0;i < V;i++)
{
for(int j = 0;j < V;j++) t[j].clear();
for(int j = 0;j < V;j++) t[i | j].pb(j);
for(int j = V - 1;j >= 0 && cnt1[i] < K;j--)
for(int k : t[j])
{
for(int c = w2[k].size() - 1;c >= 0 && cnt1[i] < K;c--) s1[i][++cnt1[i]] = w2[k][c];
if(cnt1[i] == K) break;
}
for(int j = V - 1;j >= 0 && cnt2[i] < K;j--)
for(int k : t[j])
{
for(int c = w1[k].size() - 1;c >= 0 && cnt2[i] < K;c--) s2[i][++cnt2[i]] = w1[k][c];
if(cnt2[i] == K) break;
}
}
for(int i = 1;i <= n;i++)
{
for(Edge j : p1[i]) vis[j.y] = i;
sort(p1[i].begin(),p1[i].end(),cmp1);
for(int j = 1,x = 1,y = 0;j <= K;j++)
{
while(x <= K && vis[s1[a[i]][x]] == i) x++;
if(x <= K && (y == (int)p1[i].size() || 2 * (a[i] | b[s1[a[i]][x]]) > p1[i][y].z)) p[s1[a[i]][x++]].pb(i);
else p[p1[i][y++].y].pb(i);
}
}
memset(vis,0,sizeof(vis));
for(int i = 0;i < V;i++)
{
memcpy(s1[i],s2[i],sizeof(int) * (K + 1));
sort(s1[i] + 1,s1[i] + K + 1);
}
for(int i = 1;i <= n;i++)
{
for(Edge j : p2[i]) vis[j.x] = i;
sort(p2[i].begin(),p2[i].end(),cmp1);
for(int j = 1,x = 1,y = 0;j <= K;j++)
{
while(x <= K && vis[s2[b[i]][x]] == i) x++;
if(x <= K && (y == (int)p2[i].size() || 2 * (a[s2[b[i]][x]] | b[i]) > p2[i][y].z)) used[s2[b[i]][x++]] = i;
else used[p2[i][y++].x] = i;
}
sort(p2[i].begin(),p2[i].end(),cmp2);
for(int j = 1,x = 1,y = 0,k,cur = 0,d;j <= K;j++)
{
while(x <= K && (vis[s1[b[i]][x]] == i || used[s1[b[i]][x]] != i)) x++;
while(y < (int)p2[i].size() && used[p2[i][y].x] != i) y++;
if(x <= K && (y == (int)p2[i].size() || s1[b[i]][x] < p2[i][y].x)) k = s1[b[i]][x++],d = -1;
else k = p2[i][y].x,d = p2[i][y++].z;
while(cur < (int)p[i].size() && p[i][cur] < k) cur++;
if(cur == (int)p[i].size()) break;
if(p[i][cur] == k) e.pb((Edge){k,i,d == -1 ? 2 * (a[k] | b[i]) : d});
}
}
int up = min(min((int)e.size(),2 * K * K),10000);
if(up < (int)e.size())
{
nth_element(e.begin(),e.begin() + up,e.end(),cmp1);
e.resize(up);
}
for(Edge i : e)
{
if(!id1[i.x]) id1[i.x] = ++cnt;
if(!id2[i.y]) id2[i.y] = ++cnt;
g.add_edge(id1[i.x],id2[i.y],1,i.z);
}
g.T = ++cnt;
for(int i = 1;i <= n;i++) if(id1[i]) g.add_edge(0,id1[i],1,0);
for(int i = 1;i <= n;i++) if(id2[i]) g.add_edge(id2[i],cnt,1,0);
g.ek();
}
}
namespace BBB
{
int tot,a[N],b[N],f[M][M],opt[M][M],id1[N],id2[N],p1[M],p2[M],mch1[M],mch2[M],val1[M],val2[M],c1[M],c2[M],p[M];
int head1[N],to1[N * 5],v1[N * 5],nxt1[N * 5],head2[N],to2[N * 5],v2[N * 5],nxt2[N * 5],cnt1[V],cnt2[V],cur1[V],cur2[V],s1[V][M],s2[V][M];
vector <int> t[V],w1[V],w2[V];
map <int,int> mp[N];
void get_rt(int s,int t)
{
int mid = opt[s][t];
if(!mid) return ;
get_rt(s,mid),p[++tot] = mid,get_rt(mid,t);
}
il int get_val(int x,int y)
{
int ret = 2 * (a[x] | b[y]);
if(mp[x].find(y) != mp[x].end()) ret += mp[x][y];
return ret;
}
void Main()
{
for(int i = 1;i <= n;i++) a[i] = read();
for(int i = 1;i <= n;i++) b[i] = read();
for(int i = 1;i <= n;i++) w1[a[i]].pb(i);
for(int i = 1;i <= n;i++) w2[b[i]].pb(i);
for(int i = 0;i < V;i++)
{
for(int j = 0;j < V;j++) t[j].clear();
for(int j = 0;j < V;j++) t[i | j].pb(j);
for(int j = V - 1;j >= 0;j--)
for(int k : t[j])
{
for(int c = w2[k].size() - 1;c >= 0 && cnt1[i] < K;c--) s1[i][cnt1[i]++] = w2[k][c];
for(int c = w1[k].size() - 1;c >= 0 && cnt2[i] < K;c--) s2[i][cnt2[i]++] = w1[k][c];
}
}
for(int i = 1,x,y,z;i <= m;i++)
{
x = read(),y = read(),z = read();
to1[i] = y,v1[i] = z,nxt1[i] = head1[x],head1[x] = i;
to2[i] = x,v2[i] = z,nxt2[i] = head2[y],head2[y] = i;
mp[x][y] = z;
}
for(int T = 1,sum = 0;;T++)
{
int max1 = -1,max2 = -1,s,t,u,v,tmp;
for(int i = 1;i <= n;i++)
if(!id1[i])
for(int c = head1[i],j,v;c;c = nxt1[c])
if(!id2[j = to1[c]] && max1 < (v = 2 * (a[i] | b[j]) + v1[c]))
max1 = v,s = i,t = j;
for(int i = 1,v,p;i <= n;i++)
{
if(id1[i]) continue;
v = a[i];
while(id2[p = s1[v][cur1[v]]]) cur1[v]++;
if(max1 < (tmp = 2 * (v | b[p])))
max1 = tmp,s = i,t = p;
}
for(int i = 1;i < T;i++)
for(int j = 1,d;j < T;j++)
if(max2 < (d = f[i][j] + val1[mch2[j]] + val2[i] - get_val(p1[mch2[j]],p2[j])))
max2 = d,u = i,v = j;
sum += max(max1,max2);
printf("%d ",sum);
if(T == K) break;
if(max1 >= max2)
{
id1[s] = id2[t] = T,p1[T] = s,p2[T] = t;
mch1[T] = mch2[T] = T;
}
else
{
p[tot = 1] = u,get_rt(u,v),p[++tot] = v,v = mch2[v];
for(int i = tot - 1,t;i >= 1;i--)
{
t = mch2[p[i]];
mch1[t] = p[i + 1],mch2[p[i + 1]] = t;
}
id1[c2[u]] = id2[c1[v]] = T,p1[T] = c2[u],p2[T] = c1[v];
mch1[T] = u,mch2[u] = T;
mch2[T] = v,mch1[v] = T;
}
for(int i = 1;i <= T;i++)
for(int j = 1;j <= T;j++)
if(i != j) f[i][j] = get_val(p1[mch2[i]],p2[j]) - get_val(p1[mch2[i]],p2[i]);
else f[i][j] = 0;
for(int i = 1;i <= T;i++)
for(int j = 1;j <= T;j++)
opt[i][j] = 0;
for(int k = 1,v;k <= T;k++)
for(int i = 1;i <= T;i++)
for(int j = 1;j <= T;j++)
if((v = f[i][k] + f[k][j]) > f[i][j])
f[i][j] = v,opt[i][j] = k;
for(int i = 1;i <= T;i++) val1[i] = val2[i] = -1;
for(int i = 1,maxn,p;i <= T;i++)
{
maxn = -1;
for(int c = head1[p1[i]],j,v;c;c = nxt1[c])
if(!id2[j = to1[c]] && maxn < (v = 2 * (a[p1[i]] | b[j]) + v1[c]))
maxn = v,p = j;
if(maxn > val1[i]) val1[i] = maxn,c1[i] = p;
}
for(int i = 1,v,p;i <= T;i++)
{
v = a[p1[i]];
while(id2[p = s1[v][cur1[v]]]) cur1[v]++;
if(val1[i] < (tmp = 2 * (v | b[p]))) val1[i] = tmp,c1[i] = p;
}
for(int i = 1,maxn,p;i <= T;i++)
{
maxn = -1;
for(int c = head2[p2[i]],j,v;c;c = nxt2[c])
if(!id1[j = to2[c]] && maxn < (v = 2 * (a[j] | b[p2[i]]) + v2[c]))
maxn = v,p = j;
if(maxn > val2[i]) val2[i] = maxn,c2[i] = p;
}
for(int i = 1,v,p;i <= T;i++)
{
v = b[p2[i]];
while(id1[p = s2[v][cur2[v]]]) cur2[v]++;
if(val2[i] < (tmp = 2 * (v | a[p]))) val2[i] = tmp,c2[i] = p;
}
}
puts("");
}
}
int main()
{
freopen("transfer.in","r",stdin);
freopen("transfer.out","w",stdout);
n = read(),m = read(),K = read();
if(n <= 300 && m <= 10000 && K <= 300) BBB :: Main();
else AAA :: Main();
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...