WY模拟赛9
WY模拟赛9
T1. 洛谷 P12026 [USACO25OPEN] Compatible Pairs S
对于两个可以配对的奶牛,考虑连边建图。可以发现,图上每个节点读书最多为 $ 2 $ ,如果是 $ A $ 或 $ B $ 的一半的话就是自环。
可以确定一个贪心的策略,对于一条链从两端向中间更新答案。于是我们拓扑排序并计算答案。
code:
#include <bits/stdc++.h>
#define i8 __int128
#define int long long
#define fuck inline
#define lb long double
using namespace std;
// typedef long long ll;
const int N=2e5+5,M=64,mod=536870912;
const int inf=INT_MAX,INF=1e9+7;
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118;
// const int M=mod1*mod2;
fuck int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
return x*f;
}
fuck void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
int vis[N];
int ind[N];
map<int,int>mp;
int ans,n,a,b,t,dis[N],val[N];
queue<int>q;
vector<int>g[N];
fuck void solve()
{
cin>>n>>a>>b;
for(int i=1;i<=n;i++)cin>>val[i]>>dis[i],mp[dis[i]]=i;
for(int i=1;i<=n;i++)
{
if(mp.find(a-dis[i])!=mp.end())g[i].push_back(mp[a-dis[i]]),ind[mp[a-dis[i]]]++;
if(a!=b&&mp.find(b-dis[i])!=mp.end())g[i].push_back(mp[b-dis[i]]),ind[mp[b-dis[i]]]++;
}
for(int i=1;i<=n;i++)if(ind[i]==1)q.push(i);
while(!q.empty())
{
int u=q.front();q.pop();
for(auto v:g[u])
{
if(vis[v])continue;
if(v==u)ans+=val[u]/2,vis[u]&=1;
else t=min(val[u],val[v]),ans+=t,val[u]-=t,val[v]-=t;
ind[v]--;
if(ind[v]==1)q.push(v);
}
vis[u]=1;
}
cout<<ans<<"\n";
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
// int fuckccf=read();
// int QwQ=read();
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
T2. 洛谷 P10777 BZOJ3706 反色刷
注意到询问数量非常庞大,所以需要动态维护信息。
稍微研究一下题意,很容易发现,最小操作次数就是有多少条黑色的欧拉回路。
由于每个联通块之间可能不连通,所以对每个联通块维护一个并查集,同时更新以下几个信息:
- 当前奇度黑点数量;
- 每个连通块内黑边数量;
最后动态更新并输出答案即可。
#include <bits/stdc++.h>
#define i8 __int128
#define int long long
#define fuck inline
#define lb long double
using namespace std;
// typedef long long ll;
const int N=1e6+5,M=64,mod=536870912;
const int inf=INT_MAX,INF=1e9+7;
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118;
// const int M=mod1*mod2;
fuck int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
return x*f;
}
fuck void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,m,fa[N],vis[N],b[N],frz=0;
struct node
{
int u,v,c;
}g[N];
fuck int findx(int x){return x==fa[x]?x:fa[x]=findx(fa[x]);}
fuck void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
g[i].u=x;g[i].v=y;g[i].c=z;
if(z)
{
if(vis[x])frz--;
else frz++;
vis[x]^=1;
if(vis[y])frz--;
else frz++;
vis[y]^=1;
}
if(findx(x)!=findx(y))fa[findx(x)]=fa[findx(y)];
}
int cnt=0;
for(int i=1;i<=m;i++)
{
if(g[i].c)
{
int f=findx(g[i].u);
if(!b[f])cnt++;
b[f]++;
}
}
int Q;cin>>Q;
while(Q--)
{
int op;cin>>op;
if(op==2)
{
if(frz)cout<<-1<<"\n";
else cout<<cnt<<"\n";
}
else
{
int x;cin>>x;x++;
int u=g[x].u,v=g[x].v;
if(vis[u])frz--;
if(vis[v])frz--;
vis[u]^=1;vis[v]^=1;
if(vis[u])frz++;
if(vis[v])frz++;
int rt=findx(u);
if(g[x].c)
{
g[x].c=0;
b[rt]--;
if(!b[rt])cnt--;
}
else
{
g[x].c=1;
if(!b[rt])cnt++;
b[rt]++;
}
}
}
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
// int fuckccf=read();
// int QwQ=read();
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
T3. 洛谷 P2731 [USACO3.3] 骑马修栅栏 Riding the Fences
- 两个栅栏间可能存在多条路,也就是重边;
- 初始化节点需要是原图中的一个,可能图中不存在某些节点编号。
#include <bits/stdc++.h>
#define i8 __int128
#define int long long
#define fuck inline
#define lb long double
using namespace std;
// typedef long long ll;
const int N=5e4+5,M=64,mod=998244353;
const int inf=INT_MAX,INF=1e9+7;
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118;
// const int M=mod1*mod2;
fuck int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
return x*f;
}
fuck void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
struct node
{
int u,v;
}p[N];
stack<int>st;
int a[505][505];
int ind[N];
int n,cnt1=0,cnt2=0;
fuck bool cmp(int a,int b){return a>b;}
fuck void dfs(int s)
{
for(int j=1;j<=505;j++)
{
if(a[s][j]>=1)
{
a[s][j]--;
a[j][s]--;
dfs(j);
}
}
st.push(s);
}
fuck void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>p[i].u>>p[i].v;
ind[p[i].v]++,ind[p[i].u]++;
a[p[i].u][p[i].v]++;a[p[i].v][p[i].u]++;
}
int s=p[1].u;
for(int i=1;i<=500;i++)
{
if(ind[i]==0)continue;
if(ind[i]%2==1){s=i;break;}
}
dfs(s);
while(st.size())cout<<st.top()<<"\n",st.pop();
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
// int fuckccf=read();
// int QwQ=read();
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
T4. 洛谷 P1330 封锁阳光大学
二分图染色的板子。
- 图一定联通;
- 由于每一个联通块都是随机染色,所以每次加答案时要加染色数量小的那个。
code:
#include <bits/stdc++.h>
#define i8 __int128
#define int long long
#define fuck inline
#define lb long double
using namespace std;
// typedef long long ll;
const int N=2e5+5,M=64,mod=998244353;
const int inf=INT_MAX,INF=1e9+7;
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118;
// const int M=mod1*mod2;
fuck int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
return x*f;
}
fuck void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,m;
vector<int>g[N];
int color[N],cnt1=0,cnt2=0,f=0;
fuck void rs(int x,int cl)
{
// cout<<x<<" "<<color[x]<<" "<<cl<<endl;
if(color[x]!=-1&&color[x]!=cl){cout<<"Impossible"<<"\n";exit(0);}
if(color[x]==cl){return;}
color[x]=cl;
if(cl==0)cnt1++;
else cnt2++;
for(auto v:g[x])rs(v,cl^1);
}
int ans=0;
fuck void solve()
{
memset(color,-1,sizeof(color));
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;cin>>x>>y;
g[x].push_back(y);g[y].push_back(x);
}
for(int i=1;i<=n;i++)
{
int sum1=cnt1,sum2=cnt2;
if(color[i]==-1)rs(i,0);
ans+=min(cnt1-sum1,cnt2-sum2);
}
cout<<ans<<"\n";
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
// int fuckccf=read();
// int QwQ=read();
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
总结
- 还需要巩固图论算法的模板,提高敲模板的速度与质量;
- 对于图论的题需要细致地考虑特殊情况。
- 图论的陷阱:重边,自环,图不联通等。
完结收工!!!!!

看完点赞,养成习惯
\(\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\)

浙公网安备 33010602011771号