ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 | Checkers-2019牛客暑期多校训练营第九场G题

2019-09-07 16:36:37  阅读:203  来源: 互联网

标签:return int 题解 dsu 多校 vector mp Checkers vec


题目来源于牛客竞赛:https://ac.nowcoder.com/acm/contest/discuss
题目描述:
在这里插入图片描述
输入描述:
在这里插入图片描述
输出描述:
在这里插入图片描述
示例1:
在这里插入图片描述
题解:
在这里插入图片描述
代码:

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
 
using namespace std;
using namespace __gnu_pbds;
  
#define fi first
#define se second
#define mp make_pair
#define pb push_back
  
typedef long long ll;
typedef pair<int,int> ii;
typedef vector<int> vi;
typedef unsigned long long ull;
typedef long double ld;
typedef tree<ii, null_type, less<ii>, rb_tree_tag, tree_order_statistics_node_update> pbds;
 
vector<int> fact;
vector<int> ifact;
vector<int> inv;
vector<int> pow2;
const int MOD = (1e9 + 7);
void radd(int &a, int b)
{
    a+=b;
    while(a>=MOD) a-=MOD;
}
 
int add(int a, int b)
{
    a+=b;
    while(a>=MOD) a-=MOD;
    return a;
}
int mult(int a, int b)
{
    return (a*1LL*b)%MOD;
}
int modpow(int a, int b)
{
    int r=1;
    while(b)
    {
        if(b&1) r=mult(r,a);
        a=mult(a,a);
        b>>=1;
    }
    return r;
}
int inverse(int a)
{
    return modpow(a,MOD-2);
}
void init(int _n)
{
    fact.clear(); ifact.clear(); inv.clear(); pow2.clear();
    fact.resize(_n+1);
    ifact.resize(_n+1);
    inv.resize(_n+1);
    pow2.resize(_n+1);
    pow2[0]=1;
    ifact[0]=1;
    fact[0]=1;
    for(int i=1;i<=_n;i++)
    {
        pow2[i]=add(pow2[i-1],pow2[i-1]);
        fact[i]=mult(fact[i-1],i);
        //ifact[i]=mult(ifact[i-1],inv[i]);
    }
    ifact[_n] = inverse(fact[_n]);
    for(int i=_n-1;i>=1;i--)
    {
        ifact[i] = mult(ifact[i + 1], i + 1);
    }
    for(int i=1;i<=_n;i++)
    {
        inv[i] = mult(fact[i-1],ifact[i]);
    }
}
 
const int M = 12;
const int N = 155;
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1};
const int C = 4;
 
struct DSU
{
    int S;
    struct node
    {
        int p;
    };
    vector<node> dsu;
    DSU(int n)
    {
        S = n;
        for(int i = 0; i < n; i++)
        {
            node tmp;
            tmp.p = i;
            dsu.pb(tmp);
        }
    }
    int rt(int u)
    {
        if(dsu[u].p == u) return u;
        dsu[u].p = rt(dsu[u].p);
        return dsu[u].p;
    }
    void merge(int u, int v)
    {
        u = rt(u); v = rt(v);
        if(u == v) return ;
        if(rand()&1) swap(u,v);
        dsu[v].p = u;
    }
};
 
map<vi,int> ma;
vi F[555];
const int C2 = 76;
 
vi horizontal_connect(vi conn, int bit)
{
    vi nw(C,0);
    DSU dsu(C*2+3);
    assert(conn.size()==C);
    int cur=C+1;
    for(int i=0;i+1<conn.size();i++)
    {
        if(bit&(1<<i))
        {
            if(conn[i]==0) conn[i]=cur++;
            if(conn[i+1]==0) conn[i+1]=cur++;
            dsu.merge(conn[i],conn[i+1]);
        }
    }
    int ID[C*2+3]; memset(ID,-1,sizeof(ID)); int c=1;
    ID[0]=0;
    for(int i=0;i<conn.size();i++)
    {
        if(conn[i]>0&&(dsu.rt(conn[i])==conn[i])&&ID[conn[i]]==-1)
        {
            ID[conn[i]]=c++;
        }
    }
    for(int i=0;i<conn.size();i++)
    {
        nw[i] = ID[dsu.rt(conn[i])];
    }
    int msiz=ma.size(); assert(msiz<C2);
    if(ma.find(nw)==ma.end()) {ma[nw]=msiz-1; F[msiz-1]=nw;}
    return nw;
}
 
vi vertical_connect(vi conn, int bit)
{
    vi nw(C,0); assert(conn.size()==C); set<int> S; set<int> S2;
    for(int i=0;i<conn.size();i++)
    {
        S2.insert(conn[i]);
        if(bit&(1<<i))
        {
            nw[i]=conn[i]; S.insert(nw[i]);
        }
    }
    S2.erase(0); S.erase(0);
    if(S.size()!=S2.size()) return {};
    int msiz=ma.size(); assert(msiz<C2);
    if(ma.find(nw)==ma.end()) {ma[nw]=msiz-1; F[msiz-1]=nw;}
    return nw;
}
 
int dp[N+11][(1<<C)+1][C2+1][(1<<C)+1];
 
int g(int id)
{
    vi tmp=F[id]; int bit=0;
    for(int i=0;i<C;i++)
    {
        if(tmp[i]>0) bit^=(1<<i);
    }
    return bit;
}
 
int solve_fast2(vector<ii> vec)
{
    int n = vec.size();
    if(vec.empty()) return 0;
    set<ii> S;
    for(int i=0;i<n;i++) S.insert(vec[i]);
    int ans = 0;
    //count odd degree vertices
    for(int i=0;i<N;i+=2)
    {
        for(int j=0;j<M;j+=2)
        {
            int ex=0;
            for(int d=0;d<4;d++)
            {
                if(S.find(mp(i+dx[d],j+dy[d]))!=S.end())
                {
                    ex=1; break;
                }
            }
            if(ex) ans=add(ans,pow2[n-1]);
        }
    }
    //count eulerian cycles
    ma.clear();
    ma[{}]=-1;
    vi emp(C,0); ma[emp]=0; F[0]=emp;
    memset(dp,0,sizeof(dp));
    dp[0][0][0][0]=1;
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<(1<<C);j++)
        {
            for(int k=0;k<C2;k++)
            {
                for(int l=0;l<(1<<C);l++)
                {
                    if(dp[i][j][k][l]==0) continue;
                    int v=dp[i][j][k][l];
                    if(i%2==0)
                    {
                        for(int bit=0;bit<(1<<(C-1));bit++)
                        {
                            bool pos=1; int j2=j;
                            for(int z=0;z<C-1;z++)
                            {
                                //connect (i,2z) with (i,2(z+1)) using (i,2z+1)
                                if((bit&(1<<z))>0&&S.find(mp(i,2*z+1))==S.end())
                                {
                                    pos=0; break;
                                }
                                if(bit&(1<<z)){j2^=(1<<z); j2^=(1<<(z+1));}
                            }
                            if(!pos) continue;
                            vi conn = F[k];
                            vi nw = horizontal_connect(conn, bit);
                            int cnt = 0;
                            //count new bad edges here
                            for(int z=0;z<C;z++)
                            {
                                if(conn[z]==0&&nw[z]>0) //(i,2z) just became bad
                                {
                                    if(S.find(mp(i-1,2*z))!=S.end() && !(l&(1<<z)))
                                    {
                                        cnt++;
                                    }
                                    if(S.find(mp(i+1,2*z))!=S.end())
                                    {
                                        cnt++;
                                    }
                                    //spread to left and right
                                    if(S.find(mp(i,2*z+1))!=S.end()&&conn[z+1]==0)
                                    {
                                        cnt++;
                                    }
                                    if(S.find(mp(i,2*z-1))!=S.end()&&nw[z-1]==0)
                                    {
                                        cnt++;
                                    }
                                }
                            }
                            radd(dp[i+1][j2][ma[nw]][g(k)], mult(v, inv[(1<<cnt)]));
                        }
                    }
                    else
                    {
                        for(int bit=0;bit<(1<<C);bit++)
                        {
                            bool pos=1; int j2=j;
                            for(int z=0;z<C;z++)
                            {
                                //connect (i-1,2z) and (i+1,2z) with (i,2z)
                                if((bit&(1<<z))>0&&S.find(mp(i,2*z))==S.end())
                                {
                                    pos=0; break;
                                }
                                if(bit&(1<<z)){j2^=(1<<z);}
                            }
                            if(!pos) continue;
                            if(j2!=0) continue; //or else no eulerian cycle
                            vi conn = F[k];
                            vi nw = vertical_connect(conn, bit);
                            if(nw.empty()) continue;
                            int cnt=0;
                            //count new bad edges here
                            //impossible for (i-1,2z) to be bad but become good now by parity
                            for(int z=0;z<C;z++)
                            {
                                if(nw[z]>0) //(i+1,2z) just became bad, push to all 4 directions
                                {
                                    //up not needed
                                    if(S.find(mp(i+2,2*z))!=S.end())
                                    {
                                        cnt++;
                                    }
                                    //spread to left and right
                                    if(S.find(mp(i+1,2*z+1))!=S.end())
                                    {
                                        cnt++;
                                    }
                                    if(S.find(mp(i+1,2*z-1))!=S.end()&&nw[z-1]==0)
                                    {
                                        cnt++;
                                    }
                                }
                            }
                            radd(dp[i+1][bit][ma[nw]][g(k)], mult(v, inv[(1<<cnt)]));
                        }
                    }
                }
            }
        }
    }
    vi good;
    for(auto X:ma)
    {
        if(X.fi.empty()) continue;
        int mx=0;
        for(int i=0;i<X.fi.size();i++)
        {
            mx=max(mx,X.fi[i]);
        }
        if(mx==1) good.pb(X.se);
    }
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<(1<<C);j++)
        {
            for(int k:good)
            {
                for(int l=0;l<(1<<C);l++)
                {
                    if(i%2==1&&j==0) ans=add(ans, mult(2, mult(pow2[n], dp[i][j][k][l])));
                }
            }
        }
    }
    ans = mult(ans, inv[2]);
    return ans;
}
 
int solve_fast(vector<ii> vec)
{
    int n = vec.size();
    vector<ii> V[2];
    for(int i=0;i<n;i++)
    {
        if((vec[i].fi+vec[i].se)%2==0)
        {
            vec[i].se++;
            V[0].pb(vec[i]);
        }
        else
        {
            V[1].pb(vec[i]);
        }
    }
    int ans = 0;
    for(int i=0;i<2;i++)
    {
        int sol = solve_fast2(V[i]);
        ans = add(ans, mult(pow2[int(V[i^1].size())], sol));
    }
    return ans;
}
 
void read_solve()
{
    int n; cin>>n;
    vector<ii> vec;
    for(int i=0;i<n;i++)
    {
        int x,y; cin>>x>>y;
        vec.pb(mp(x,y));
    }
    cout<<solve_fast(vec)<<'\n';
}
 
int main()
{
    ios_base::sync_with_stdio(0); cin.tie(0);
    init(255555);
    read_solve();
}

更多问题,更详细题解可关注牛客竞赛区,一个刷题、比赛、分享的社区。
传送门:https://ac.nowcoder.com/acm/contest/discuss

标签:return,int,题解,dsu,多校,vector,mp,Checkers,vec
来源: https://blog.csdn.net/lastbye/article/details/100600926

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有