码迷,mamicode.com
首页 > 其他好文 > 详细

暑期集训日志

时间:2019-07-12 09:18:38      阅读:96      评论:0      收藏:0      [点我收藏+]

标签:return   first   ring   lan   hide   策略   最大   def   c++   

章·二:7-12:男儿何不带吴钩,收取关山五十州


 ·今日进度技术图片

暂无进度(玩命加载中……)

 

 

·随手记:

6:04

新的一天!loj不大友好。刚才听邻铺的lockey大佬说第三题是基环树。

那是啥……蒟蒻我不会啊QAQ。学习去QAQ。

 

章·一:7-11:昨夜西风凋碧树,独上高楼,望尽天涯路


 技术图片·今日进度

[图论]B.「矩阵游戏」(二分图模板)

好多人问我……

以为说一下二分图你们就能秒懂……

写个题解。

行建点,列建点,黑格做边,匈牙利算法求最大匹配。

最后看最大匹配是否是完美匹配就odk。

顺便说一句:我没颓题解!

技术图片
/*
警戒!警戒!
多判题目!
「抵制克苏恩」血的教训……
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define read(a) a=init()
#define rint register int
using namespace std;
int T,n,map[203][203],cx[203],cy[203];
int sum0,ans=0;
bool h=false,wr=false,vis[203];
inline int init()
{
    int a=0,b=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)b=-1;ch=getchar();}
    while(ch>=0&&ch<=9){a=(a<<3)+(a<<1)+(ch-0);ch=getchar();}
    return a*b;
}
inline bool find(int u)
{
    for(register int i=1;i<=n;++i)
        if(map[u][i]&&!vis[i])
        {
            vis[i]=true;
            if(cy[i]==-1||find(cy[i]))
            {
                cx[u]=i,cy[i]=u;
                return 1;
            }
        }
    return 0;
}
int main()
{
    read(T);
    while(T--)
    {
        read(n);wr=false;ans=0;
        memset(cx,-1,sizeof(cx));
        memset(cy,-1,sizeof(cy));
        for(rint i=1;i<=n;++i)
        {
            h=false;
            for(rint j=1;j<=n;++j)
            {
                read(map[i][j]);
                if(map[i][j])sum0++,h=true;
            }
            if(!h)wr=true;
        }
//        cout<<sum0<<endl;
        if(sum0<n||wr){cout<<"No"<<endl;continue;}
        for(rint i=1;i<=n;++i)
        {
            h=false;
            for(rint j=1;j<=n;++j)
                if(map[j][i])h=true;
            if(!h)wr=true;
        }
        if(wr){cout<<"No"<<endl;continue;}
        for(rint i=1;i<=n;++i)
        {
            memset(vis,0,sizeof(vis));
            ans+=find(i);
        }
        if(ans==n)cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}
View Code

放一个匈牙利算法模板,转自https://blog.csdn.net/qq_40938077/article/details/80410356

技术图片
#include<bits/stdc++.h>
#define MAXN 9999
using namespace std;
int nx,ny;//nx表示二分图左边顶点的个数,ny表示二分图右边顶点的个数
int m;//m代表边的条数
int cx[MAXN],cy[MAXN];//如果有cx[i]=j,则必有cy[j]=i,说明i点和j点能够匹配
int x,y;//x点到y点有边
int e[MAXN][MAXN];//邻接矩阵
int visited[MAXN];//标记数组,标记的永远是二分图右边的顶点
int ret;//最后结果
int point(int u)//这个函数的作用是寻找增广路和更新cx,xy数组,如果找到了增广路,函数返回1,找不到,函数返回0。
{
    for(int v=1;v<=ny;v++)//依次遍历右边的所有顶点
    {
        if(e[u][v]&&!visited[v])//条件一:左边的u顶点和右边的v顶点有连通边,条件二:右边的v顶点在没有被访问过,这两个条件必须同时满足
        {
            visited[v]=1;//将v顶点标记为访问过的
            if(cy[v]==-1||point(cy[v]))//条件一:右边的v顶点没有左边对应的匹配的点,条件二:以v顶点在左边的匹配点为起点能够找到一条增广路(如果能够到达条件二,说明v顶点在左边一定有对应的匹配点)。
            {
                cx[u]=v;//更新cx,cy数组
                cy[v]=u;
                return 1;
            }
        }
    }
    return 0;//如果程序到达了这里,说明对右边所有的顶点都访问完了,没有满足条件的。
}
int main()
{
    while (cin>>m>>nx>>ny)
    {
        memset(cx,-1,sizeof(cx));//初始化cx,cy数组的值为-1
        memset(cy,-1,sizeof(cy));
        memset(e,0,sizeof(e));//初始化邻接矩阵
        ret=0;
        while(m--)//输入边的信息和更新邻接矩阵
        {
            cin>>x>>y;
            e[x][y]=1;
        }
        for(int i=1;i<=nx;i++)//对二分图左边的所有顶点进行遍历
        {
            if(cx[i]==-1)//如果左边的i顶点还没有匹配的点,就对i顶点进行匹配
            {
                memset(visited,0,sizeof(visited));//每次进行point时,都要对visited数组进行初始化
                ret+=point(i);//point函数传入的参数永远是二分图左边的点
            }
        }
        cout<<ret<<endl;
    }
}
匈牙利

[图论]A.「菜肴制作」(拓扑排序+大根堆)

倒序建边,跑拓扑序。

(为什么倒序?贪心策略错啦!你正序连样例第三组数据都跑不过。)

另外,多判一定要把所有参数全部清空。

多判不清空,爆零两行泪。(没清空tot我调了半小时……)

特判impossible比较奇诡。Larry点了一下我才想出来。

技术图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#define rint register int
using namespace std;
int T,n,m,a,b,tot,first[100003];
int du[100003];
struct node{
    int u,v,nxt;
};
bool pan=0,vis[100003];
inline void add(int uu,int vv,node edge[])
{
    ++tot;
    edge[tot].u=uu;
    edge[tot].v=vv;
    edge[tot].nxt=first[uu];
    first[uu]=tot;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        memset(vis,0,sizeof(vis));
        memset(du,0,sizeof(du));
        memset(first,0,sizeof(first));
        tot=0;
        priority_queue <int> q;
        stack <int> s;
        node edge[100003];
        for(rint i=1;i<=m;++i)
        {
            scanf("%d %d",&a,&b);
            add(b,a,edge);du[a]++;
        }
        for(rint i=1;i<=n;++i)
        {
            if(!du[i])q.push(i);
            vis[i]=1;
        }
        if(q.empty()){cout<<"Impossible!"<<endl;continue;}
        while(!q.empty())
        {
            int xx=q.top();s.push(xx);q.pop();
//            cout<<xx<<endl;
            pan=0;
            for(rint i=first[xx];i;i=edge[i].nxt)
            {
                int yy=edge[i].v;
                du[yy]--;
                if(!du[yy])
                {
                    pan=1;
                    q.push(yy);
//                    cout<<"yy"<<yy<<endl;
                    vis[yy]=1;
                }
            }
//            if(pan==0&&q.empty()){cout<<"Impossible!"<<endl;break;}
        }
//        if(pan==0)continue;
        if(s.size()!=n){cout<<"Impossible!"<<endl;continue;}
        while(!s.empty())
        {
            cout<<s.top()<< ;
            s.pop();
        }
        cout<<endl;
    }
}
View Code

 [图论]I.「软件安装」(tarjan缩点+神仙dp)

看完题我想到了某道ppt原题:很郁闷的金明。对着树形dp的ppt就是一顿yy。然后开始打。

打了半天dp一分没拿。我意识到有点不大对。

问了大佬说是有环,要跑一边tarjan缩点。我一阵猛缩,调了一下午,改了十多个参数(颓了题解),终于……80分。

崩溃了的我一边自嘲一边开大了数组,AC!wtf!

技术图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#define rint register int
using namespace std;
int tot_e,cnt,n,m,w[202],v[202],d[202],dfn[202],low[202];
int tot_q,belong[202],qw[202],qv[202],first[202],deg[202];
int count[202],list[202],tpt=0,dp[202][505],first2[202],tot_e2;
bool instack[202];
struct node{int u,v,nxt;}edge[202],edge2[202];
struct data{int fa,lc,rc;}tree[202];
stack <int> s;
inline void add(int uu,int vv)
{
    ++tot_e;
    edge[tot_e].u=uu;
    edge[tot_e].v=vv;
    edge[tot_e].nxt=first[uu];
    first[uu]=tot_e;
}
inline void add2(int uu,int vv)
{
    ++tot_e2;
    edge2[tot_e2].u=uu;
    edge2[tot_e2].v=vv;
    edge2[tot_e2].nxt=first2[uu];
    first2[uu]=tot_e2;
}
inline void tarjan(int x)
{
    dfn[x]=low[x]=++cnt;
    s.push(x);instack[x]=true;
    for(rint i=first[x];i;i=edge[i].nxt)
    {
        int y=edge[i].v;
        if(!dfn[y])
        {
            tarjan(y);
            low[x]=min(low[y],low[x]);
        }
        else if(instack[y])
            low[x]=min(dfn[y],low[x]);
    }
    if(dfn[x]==low[x])
    {
        ++tot_q;
        while(1)
        {
            int lin=s.top();
            s.pop();instack[lin]=false;
            belong[lin]=tot_q;
            qw[tot_q]+=w[lin];qv[tot_q]+=v[lin];
            if(lin==x) break;
        }
    }
}
inline void dfs(int x)
{
    for(rint i=first2[x];i;i=edge2[i].nxt)
    {
        int to=edge2[i].v;
        dfs(to);
        for(rint j=m;j>=0;--j)
        {
            for(rint p=0;p<=j;++p)
                dp[x][j]=max(dp[x][j],dp[to][p]+dp[x][j-p]);
        }
    }
    for(rint i=m;i>=0;--i)
    {
        if(i>=qw[x]) dp[x][i]=dp[x][i-qw[x]]+qv[x];
        else dp[x][i]=0;
    }
}
int main()
{
    scanf("%d %d",&n,&m);
    for(rint i=1;i<=n;++i)scanf("%d",&w[i]);
    for(rint i=1;i<=n;++i)scanf("%d",&v[i]);
    for(rint i=1;i<=n;++i)
    {
        scanf("%d",&d[i]);
        if(d[i]) add(d[i],i);
    }
    for(rint i=1;i<=n;++i)
        if(!dfn[i])tarjan(i);
    for(rint i=1;i<=n;++i)
    {
        if(!d[i]) continue;
        if(belong[i]==belong[d[i]]) continue;
        add2(belong[d[i]],belong[i]);deg[belong[i]]++;
    }
/*
    for(rint x=1;x<=n;x++)
    {
        if(!d[x])continue;
        for(rint i=first[x];i;i=edge[i].nxt)
        {
            if(belong[x]==belong[edge[i].v])continue;
            add2(belong[x],belong[edge[i].v]);
            deg[belong[edge[i].v]]++;
        }
    }
*/
    for(rint i=1;i<=tot_q;i++)
        if(!deg[i])add2(tot_q+1,i);
    dfs(tot_q+1);
    cout<<dp[tot_q+1][m]<<endl;
    return 0;
}
View Code

[图论]D.「tree」(最小生成树+二分答案)

读完题和利哥讨论了一会儿没思路。找天皇问了一下,(我在天皇眼里看到了……无奈?)

天皇和萌巨佬争相吐槽说这道题有问题。代码诡异,标程都不对,还说他们颓了题解(此处省略一千字)

我晕头转向,回来就心安理得的颓了个题解,打了,一个小时,A了?传说中的诡异没有出现?

后悔颓题解了(得了便宜+买乖

技术图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<algorithm>
#define rint register int
using namespace std;
int n,m,need,l,r,cnt,tot,ans;
int u[100005],v[100005],c[100005],col[100005];
int fa[100005];
struct node {int u,v,c,col;}edge[100005];
inline int read()
{
    int a=0,b=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)b=-1;ch=getchar();}
    while(ch>=0&&ch<=9){a=(a<<3)+(a<<1)+(ch-0);ch=getchar();}
    return a*b;
}
inline bool cmp(node a,node b){return a.c==b.c?a.col<b.col:a.c<b.c;}
inline int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);}
inline bool kruskal(int x)
{
    int f1,f2,sum=0;
    for(rint i=1;i<=n;i++) fa[i]=i;
    for(rint i=1;i<=m;i++)
    {
        edge[i].u=u[i];
        edge[i].v=v[i];
        edge[i].c=c[i];
        edge[i].col=col[i];
        if(!col[i]) edge[i].c+=x;
    }
    sort(edge+1,edge+m+1,cmp);
    for(rint i=1;i<=m;i++)
    {
        f1=get(edge[i].u),f2=get(edge[i].v);
        if(f1!=f2)
        {
            fa[f1]=f2;
            sum++;
            tot+=edge[i].c;
            if(!edge[i].col) cnt++;
        }
        if(sum==n-1)
            if(cnt>=need)return 1;
            else return 0;
    }
}
int main()
{
    n=read(),m=read(),need=read();
    for(rint i=1;i<=m;i++)
    u[i]=read()+1,v[i]=read()+1,c[i]=read(),col[i]=read();
    l=-101,r=101;
    while(l<r)
    {
        tot=cnt=0;
        int mid=(l+r)>>1;
        if(kruskal(mid))
            l=mid+1,ans=tot-need*mid;
        else r=mid;
    }
    cout<<ans<<endl;
    return 0;
}
View Code

·随手记

11:21

为了给我们压力,老师把山大附中的拉到了oj里。然后就展开了拉锯战。压力山大。(对面就是山大附中啊……)

不知道对面是不是以前打过这些题目。初期我们竟然失利了……前二被对方雄据。而且所有题居然都是1A!?怀疑对方颓了题解。

劳资不服!虽然弱,但我要刚上去!第一A了三道,我是两道。差一点啊啊。

我不颓题解,我认真。

11:45

NC哥夺回第一,NC哥威武!

完了我有点懈怠了……要吃饭了啊QAQ我要继续努力啊~

13:56

中午竟然有人没回宿舍午休……&……%¥#@我怎么没想到……

下午回来排行榜第一依旧是NC哥。过题数变成了四个。

同样变成四个的还有山大附中的一个人。无力感

继续努力。

15:19

山大附中都是什么人啊……在外网交付评测,攒够题目直接往oj上砸……

NC哥的rank1被半路杀出来的一个山大附中的夺走了。

这人五分钟A掉了五道题……他嗑药了么……

盘他!

19:04

我终于AC啦!!!垂死病中惊坐起,谈笑风生又一年!

调了一个下午,请了诸多大佬,挨了无数顿数落,查了许多题解我终于AC了!

我打了三个多小时打错了才颓的代码能不能从轻处理……

但是被大佬们落的好远啊……/一头撞死/生无可恋

继续努力!

21:07

又A掉了一道tree(水题?)Kruskal算法。

感觉今天复习了好多美妙图论算法,怪不得教练说这里面啥都有……

总结一下今天复习了:拓扑、二分图(增广路以及匈牙利算法)、树归、最小生成树(Kruskal)。

奇怪的是开专题以前一直以为占主要部分的最短路类题目竟然一道都没遇到??

今天还是有点颓废了。写的东西有点多啊……

序章:7-10:愿乘长风破万里浪


明天开始集训咕咕咕~

我该怎么庆祝不考期末

距离noip还有四个月。我还是那么菜鸡。我好慌啊……

暑期好好补补。

约法三章

首先是绝对不能被干回去。大假期集训内容那么紧。被干回去以我的水平肯定完了。(不被干回去也够呛

其次是尽量不颓废。之前集训的时候颓的太厉害导致水平低下……(说的好听做起来……)反正我会努力的,请机房诸位神佬监督。

第三是尽量不颓题解,坚决不颓代码(模板除外啊~蒟蒻弱弱地申辩)。

警戒·禁区:

1.白天尽量不写详细题解颓废,到晚上择一天中有用的部分写详细题解。

2.不能过于颓废,不能出现重大违纪行为(比如某学长曾……(此处省略一千字简介))

3.禁止出现利用网络之便玩游戏、看小说行为。

继续去改0707的T2……今天只A掉了一道T3……

我好菜啊……

暑期集训日志

标签:return   first   ring   lan   hide   策略   最大   def   c++   

原文地址:https://www.cnblogs.com/xingmi-weiyouni/p/11166567.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!