2020牛客暑期多校训练营(第八场)GIK

G:

枚举两维+hash。

但更简单的做法是:直接暴力三维枚举,因为最多20个不能组成一个set。

#include 
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e3+7;
 
char s[M];
struct node{
    int a[5];
}p[M];
unordered_mapmp;
unordered_mapvs;
int main()
{
    int T;
    scanf("%d",&T);
    mp['n']=1;mp['w']=2;mp['h']=3;
    mp['i']=1;mp['q']=2;mp['v']=3;
    mp['o']=1;mp['t']=2;mp['p']=3;
    mp['e']=1;mp['r']=2;mp['u']=3;
    mp['*']=4;
    for(int CA=1;CA<=T;CA++)
    {
        vs.clear();
        int N;
        scanf("%d",&N);
        for(int i=1;i<=N;i++)
        {
            scanf("%s",s);
            int n=strlen(s);
            int tp=0;
            for(int j=0;jv[5];
                    for(int k=1;k<=4;k++)v[k].clear();
                    for(int k=1;k<=4;k++)
                    {
                        v[k].pb(4);
                        if(p[i].a[k]==4||p[j].a[k]==4)
                            v[k].pb(1),v[k].pb(2),v[k].pb(3);
                        else
                        {
                        //  if(i==1&&j==4)cout<

I:

一论游戏ai,bi,连边,建图。

显然环上所有点都可以选到。

而度数为1的点能选尽量选(因为选他只会影响到其连接的点,而选其连接的点会影响更多的点,得不偿失)

所以直接拓扑排序跑一边记录即可。

 

还有一个做法是:把边拆成点,如下图:

左部点表示离散后的每个数,右部点每个点都表示一条边,连接左部图两个点,显然每条边连的两个点只能选一个。

这个图的最大匹配刚好是答案。跑网络流二分图即可。(卡常,用一些优化和剪枝可以过,我T了,但有人过了)

 

给出拓扑排序的做法:

#include
using namespace std;
const int M=2e5+7;
int head[M],cnt=1;
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
 
struct no{
    int x,y;
}p[M];
int sz,li[M];
int du[M];
int vs[M];
int main()
{
    int T;
    cin>>T;
    for(int CA=1 ;CA<=T;CA++)
    {
        cnt=1;
        sz=0;
        memset(head,0,sizeof(head));memset(vs,0,sizeof(vs));
        memset(du,0,sizeof(du));
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            li[++sz]=u;li[++sz]=v;
            p[i]=no{u,v};
        }
        sort(li+1,li+1+sz);
        sz=unique(li+1,li+1+sz)-(li+1);
        for(int i=1;i<=n;i++)
        {
            int u=lower_bound(li+1,li+1+sz,p[i].x)-li;
            int v=lower_bound(li+1,li+1+sz,p[i].y)-li;
            add(u,v,1);
            add(v,u,1);
            du[u]++;du[v]++;
        }
        queueq;
        for(int i=1;i<=sz;i++)
            if(du[i]==1)q.push(i);
        while(q.size())
        {
            int x=q.front();q.pop();
            for(int i=head[x];i;i=ee[i].nxt)
            {
                int y=ee[i].to;
                if(vs[y])continue;
                du[y]--;
                vs[x]=1;
                if(du[y]==1)q.push(y);
            }
        }
        int ans=0;
        for(int i=1;i<=sz;i++)if(vs[i]||du[i]!=0)ans++;
        printf("Case #%d: %d\n",CA,ans);
    }
    return 0;
}

K:

招待客人最大数量一定是b[1]。

然后进行贪心选择即可。

我为了省去思维量,直接用线段树维护了。。

#include 
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
const int inf=1e9+7;
const int M = 1e5+7;
int mn[M<<2],tg[M<<2];
ll a[M],b[M];
void bd(int o,int l,int r)
{
    tg[o]=0;
    if(l==r)
    {
        mn[o]=b[l];
        return ;
    }
    int m=(l+r)/2;
    bd(ls,l,m);
    bd(rs,m+1,r);
    mn[o]=min(mn[ls],mn[rs]);
}
void pd(int o,int l,int r)
{
    if(!tg[o])return ;
    tg[ls]+=tg[o];
    tg[rs]+=tg[o];
    int m=(l+r)/2;
    mn[ls]+=tg[o];
    mn[rs]+=tg[o];
    tg[o]=0;
}
void up(int o,int l,int r,int x,int y,int d)//区间加法
{
    if(x<=l&&r<=y)
    {
        tg[o]+=d;mn[o]+=d;
        return ;
    }
    pd(o,l,r);
    int m=(l+r)/2;
    if(x<=m)up(ls,l,m,x,y,d);
    if(y>m)up(rs,m+1,r,x,y,d);
    mn[o]=min(mn[ls],mn[rs]);
}
struct node{
    int sm,mn,mx;
}tr[M];
int R,n;
void qu(int o,int l,int r)
{
//  cout<'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
 
inline void write(__int128 x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}
 
ll dp[M],id[M],sum[M];
int main()
{
    int T;
    cin>>T;
    for(int CA=1;CA<=T;CA++)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
        for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
        dp[1]=a[1],id[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(sum[i]>dp[i-1])dp[i]=sum[i],id[i]=i;
            else dp[i]=dp[i-1],id[i]=id[i-1];
            //cout<<"---    "<

 

你可能感兴趣的:(2020多校牛客)