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 反色刷

原题

注意到询问数量非常庞大,所以需要动态维护信息。

稍微研究一下题意,很容易发现,最小操作次数就是有多少条黑色的欧拉回路。

由于每个联通块之间可能不连通,所以对每个联通块维护一个并查集,同时更新以下几个信息:

  1. 当前奇度黑点数量;
  2. 每个连通块内黑边数量;

最后动态更新并输出答案即可。

#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

原题

  1. 两个栅栏间可能存在多条路,也就是重边;
  2. 初始化节点需要是原图中的一个,可能图中不存在某些节点编号。
#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 封锁阳光大学

原题

二分图染色的板子。

  1. 图一定联通;
  2. 由于每一个联通块都是随机染色,所以每次加答案时要加染色数量小的那个。

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






总结

  1. 还需要巩固图论算法的模板,提高敲模板的速度与质量;
  2. 对于图论的题需要细致地考虑特殊情况。
  3. 图论的陷阱:重边,自环,图不联通等。

完结收工!!!!!

个人主页

看完点赞,养成习惯

\(\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\)

posted @ 2025-07-13 21:03  Nightmares_oi  阅读(18)  评论(0)    收藏  举报