题解:百度之星·2018·资格赛

水平有限,目前只写了其中五题…

调查问卷

借助位运算可以很快出解。

#include<bits/stdc++.h>
using namespace std;
const int N=1023;
char s[N];
int kase,ans,t,n,m,k,a[N];
int main()
{
    for(scanf("%d",&t); t--; printf("Case #%d: %d\n",++kase,ans))
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=ans=0; i<n; ++i)
        {
            scanf("%s",s);
            for(int j=a[i]=0; j<m; ++j)a[i]|=(s[j]=='A')<<j;
        }
        for(int p=1<<m; --p;)
        {
            vector<int> mp(p+1,0);
            for(int i=0; i<n; ++i)++mp[p&a[i]];
            for(int i=m=0; i<mp.size(); ++i)
                if(m+=mp[i]*(n-mp[i]),m>=k*2)
                {
                    ++ans;
                    break;
                }
        }
    }
}

子串查询

#include<bits/stdc++.h>
using namespace std;
const int N=100009;
char s[N];
int kase,t,n,q,a[N][26];
int main()
{
    for(scanf("%d",&t); t--;)
    {
        printf("Case #%d:\n",++kase);
        scanf("%d%d%s",&n,&q,&s);
        for(int i=0; i<n; ++i)
            copy(a[i],a[i]+26,a[i+1]),++a[i+1][s[i]-'A'];
        for(int i=0,l,r; i<q; ++i)
        {
            scanf("%d%d",&l,&r);
            for(int j=0; j<26; ++j)
                if(a[r][j]!=a[l-1][j])
                {
                    printf("%d\n",a[r][j]-a[l-1][j]);
                    break;
                }
        }
    }
}

整数规划

裸的KM最小权匹配。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=255,NPOS=-1;
const ll INF=1e18;
struct Matrix
{
    int n;
    ll a[N][N];
};
struct KuhnMunkres:Matrix
{
    ll hl[N],hr[N],slk[N];
    int fl[N],fr[N],vl[N],vr[N],pre[N],q[N],ql,qr;
    int check(int i)
    {
        if(vl[i]=1,fl[i]!=NPOS)return vr[q[qr++]=fl[i]]=1;
        while(i!=NPOS)swap(i,fr[fl[i]=pre[i]]);
        return 0;
    }
    void bfs(int s)
    {
        fill(slk,slk+n,INF),fill(vl,vl+n,0),fill(vr,vr+n,0);
        for(vr[q[ql=0]=s]=qr=1;;)
        {
            for(ll d; ql<qr;)
                for(int i=0,j=q[ql++]; i<n; ++i)
                    if(d=hl[i]+hr[j]-a[i][j],!vl[i]&&slk[i]>=d)
                        if(pre[i]=j,d)slk[i]=d;
                        else if(!check(i))return;
            ll d=INF;
            for(int i=0; i<n; ++i)
                if(!vl[i]&&d>slk[i])d=slk[i];
            for(int i=0; i<n; ++i)
            {
                if(vl[i])hl[i]+=d;
                else slk[i]-=d;
                if(vr[i])hr[i]-=d;
            }
            for(int i=0; i<n; ++i)
                if(!vl[i]&&!slk[i]&&!check(i))return;
        }
    }
    void ask()
    {
        fill(fl,fl+n,NPOS),fill(fr,fr+n,NPOS),fill(hr,hr+n,0);
        for(int i=0; i<n; ++i)hl[i]=*max_element(a[i],a[i]+n);
        for(int j=0; j<n; ++j)bfs(j);
    }
} km;
int main()
{
    int t,kase=0;
    for(scanf("%d",&t); t--;)
    {
        scanf("%d",&km.n);
        for(int i=0; i<km.n; ++i)
            for(int j=0; j<km.n; ++j)
                scanf("%lld",&km.a[i][j]),km.a[i][j]*=-1;
        km.ask();
        ll ans=0;
        for(int i=0; i<km.n; ++i)ans-=km.a[i][km.fl[i]];
        printf("Case #%d: %lld\n",++kase,ans);
    }
}

点集划分

//假装这里有代码

序列计数

用树状数组维护lis。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+7,M=1e9+7;
typedef int ll;
struct BaseFenwick
{
    vector<ll> v;
    BaseFenwick(int N):v(N+1,0) {}
    void add(int x,ll w)
    {
        for(; x<v.size(); x+=x&-x)v[x]=(v[x]+w)%M;
    }
    ll ask(int x)
    {
        ll r=0;
        for(; x; x-=x&-x)r=(r+v[x])%M;
        return r;
    }
};
int t,kase,n,c[N],a[N],siz;
int main()
{
    for(scanf("%d",&t); t--; printf("\n"))
    {
        scanf("%d",&n);
        for(int i=0; i<n; ++i)
            scanf("%d",&a[i]),c[i]=1;
        printf("Case #%d:",++kase);
        for(long long r=siz=n; r; --siz)
        {
            printf(" %lld",r%M);
            BaseFenwick t(n);
            for(int i=r=0; i<n; ++i)
                t.add(a[i],c[i]),c[i]=t.ask(a[i]-1),r=(r+c[i])%M;
        }
        while(siz--)printf(" 0");
    }
}

三原色图

按两种方法分别求MST然后从小往里加边,对于每个m在两个结果取较优的那个。

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
struct UnionFindSet:vector<int>
{
    int siz;
    UnionFindSet(int n):siz(n)
    {
        for(int i=0; i<n; ++i)push_back(i);
    }
    int fa(int u)
    {
        return at(u)!=u?at(u)=fa(at(u)):u;
    }
    void merge(int u,int w)
    {
        if(w=fa(w),u=fa(u),w!=u)at(w)=u,--siz;
    }
};
struct Edge
{
    int id,from,to,dist;
    bool operator<(const Edge &e)
    {
        return dist<e.dist;
    }
};
void kruskal(int n,int m,const vector<Edge> &ed,vector<Edge> &e,vector<int> &s)
{
    int ret=0;
    UnionFindSet ufs(n);
    for(sort(e.rbegin(),e.rend()); !e.empty(); e.pop_back())
        if(ufs.fa(e.back().from)!=ufs.fa(e.back().to))
        {
            ufs.merge(e.back().from,e.back().to);
            ret+=e.back().dist;
            s[e.back().id]=1;
        }
    for(int i=0; i<ed.size(); ++i)
        if(!s[ed[i].id])e.push_back(ed[i]);
    s.assign(m,INF);
    if(ufs.siz>1)return;
    sort(e.rbegin(),e.rend());
    for(int i=n-2; i<s.size(); ++i)
    {
        if(i>=0)s[i]=ret;
        if(e.empty())ret=INF;
        else ret+=e.back().dist,e.pop_back();
    }
}
char s[9];
int kase,t,n,m;
int main()
{
    for(scanf("%d",&t); t--;)
    {
        scanf("%d%d",&n,&m);
        vector<Edge> rg,gb,e;
        vector<int> r(m,0),b(m,0);
        for(Edge ed= {0}; ed.id<m; ++ed.id)
        {
            scanf("%d%d%d%s",&ed.from,&ed.to,&ed.dist,s);
            --ed.from,--ed.to,e.push_back(ed);
            if(s[0]!='B')rg.push_back(ed);
            if(s[0]!='R')gb.push_back(ed);
        }
        kruskal(n,m,e,rg,r),kruskal(n,m,e,gb,b);
        printf("Case #%d:\n",++kase);
        for(int i=0; i<m; ++i)
            printf("%d\n",min(r[i],b[i])<INF?min(r[i],b[i]):-1);
    }
}

猜你喜欢

转载自blog.csdn.net/w_weilan/article/details/81491101